Build APM บน Windows ตอนที่ 5: คอมไพล์ ImageMagick 7 ให้ PHP imagick
ตอนนี้ได้ไฟล์สองกองที่ PHP ต้องใช้ในตอนหน้า คือ DLL สำหรับรัน กับ header และ lib สำหรับคอมไพล์ extension imagick และมีแพตช์เดียวที่ต้องแก้ใน toolchain ทางการ ซึ่งถ้าไม่แก้ build จะล้มด้วย error ที่ไม่บอกวิธีแก้
พอดีในชุด extension ที่ผมต้องให้ APM ตรงกับเครื่อง production มี imagick อยู่ด้วย และ imagick ไม่ใช่ extension ที่คอมไพล์ได้ลอย ๆ มันต้องมี ImageMagick 7 ที่ build ไว้แล้วบนเครื่อง ทั้งไฟล์ header, ไฟล์ .lib สำหรับลิงก์ และ DLL สำหรับรัน ตอนนี้เลยเป็นตอนที่พา build ImageMagick ขึ้นมาก่อน ตอนที่ 6 ค่อยเอาไปประกอบกับ PHP ผมจะเขียนให้ละเอียดแบบทำตามได้ทุกขั้น โดยบอกทุกครั้งว่าใช้ terminal ตัวไหน โฟลเดอร์ไหน และผลที่ควรเห็นคืออะไร
ถ้าเพิ่งเข้ามาตอนนี้ เริ่มจาก สารบัญของซีรีส์ ก่อนได้ ตอนที่ 1 ถึง 4 เตรียมเครื่องมือ ดาวน์โหลด source build Apache และ MariaDB ไว้แล้ว ทุก path ในบทความนี้อิงว่าชุดสคริปต์อยู่ที่ C:\apm-build
ตอนนี้ทำอะไร และใช้เวลาเท่าไร
ImageMagick บน Windows ไม่ได้ build ด้วย CMake แบบตอนก่อน ๆ ทีมของเขาทำ toolchain แยกไว้ที่ github.com/ImageMagick/Windows ซึ่งเป็นชุดสคริปต์ที่ clone ImageMagick กับไลบรารีที่มันเรียกใช้ (เรียกว่า delegate เช่น jpeg, png, webp, heif, tiff, freetype, lcms) มารวมกันราว 40 repo แล้วสร้าง solution ของ Visual Studio ให้ build ทั้งหมดด้วย MSBuild สคริปต์ scripts\25-imagemagick.ps1 ของเราห่อกระบวนการนี้ไว้และเติมสิ่งที่ขาดสองอย่าง คือแก้ค่า channel mask และจัดโฟลเดอร์ผลลัพธ์ให้ imagick ใช้
เวลาวัดจากเครื่องผม (Windows 11 x64, i5-12500H, RAM 32 GB) รอบแรกคือ clone ราว 40 repo รวมกับ build ราว 170 DLL ส่วนรันซ้ำ 3.3 นาทีคือรอบที่วัดเมื่อวันที่ 22 ตุลาคม 2026 ตอน cache ยังอยู่ ขนาด 2.8 GB คือโฟลเดอร์ src\imagemagick-windows ทั้งก้อนหลัง build เสร็จ ส่วน 175 คือจำนวนไฟล์ .dll ที่ผมนับในโฟลเดอร์ Artifacts\bin หลัง build (31 ตัวในนั้นเป็น CORE_RL_*)
ตอนนี้ไม่ต้องใช้ vcpkg และไม่ต้องรอผลของ Apache กับ MariaDB สิ่งที่ต้องมีมีห้าอย่างตามนี้ ผมให้ตรวจทีละอย่างในหัวข้อถัดไป
- Visual Studio 2022 Build Tools พร้อม component ATL และ ATLMFC (ตอนที่ 1)
- Git for Windows ที่ติดตั้งแบบปกติ เพราะสคริปต์เรียก
bash.exeของ Git - NASM ใน
C:\apm-build\toolchain\nasm(ตอนที่ 2) - อินเทอร์เน็ต เพราะต้อง clone จาก GitHub ราว 40 repo
- พื้นที่ดิสก์ว่างอย่างน้อย 10 GB สำหรับตอนนี้โดยเฉพาะ (รวมทั้งซีรีส์ต้องมี 60 GB ตามที่ตอนที่ 1 บอก)
ตรวจความพร้อมก่อนเริ่ม
ขั้นที่ 1: เปิด PowerShell 7 แบบ user ปกติ
เปิด Start พิมพ์ pwsh เลือก PowerShell 7 ห้ามใช้ Run as administrator ตัว build ทั้งชุดไม่ต้องการสิทธิ์ admin
ขั้นที่ 2: เข้าโฟลเดอร์ชุดสคริปต์
Set-Location C:\apm-build
คำสั่งนี้เงียบเวลาสำเร็จ ตรวจด้วย Get-ChildItem -Name ต้องเห็น build.cmd กับโฟลเดอร์ scripts
ขั้นที่ 3: ตรวจว่าเลข tag ใน versions.json คือ 7.1.2-34
(Get-Content C:\apm-build\versions.json -Raw | ConvertFrom-Json).sources.imagemagick.version
ผลที่ควรเห็น
7.1.2-34
ค่านี้คือ git tag ของ ImageMagick ไม่ใช่ URL ดาวน์โหลด (ในไฟล์ช่อง url ของตัวนี้เป็น null และมีหมายเหตุบอกว่าสคริปต์ 25-imagemagick.ps1 เป็นคน clone)
ขั้นที่ 4: ตรวจว่าเครื่องมีบริการของ Git bash
Test-Path "$env:ProgramFiles\Git\bin\bash.exe"
ต้องได้ True สคริปต์เรียก path นี้ตรง ๆ เพื่อรัน clone-repositories.sh ถ้าได้ False แปลว่า Git ลงที่อื่นหรือยังไม่ได้ลง ให้กลับไปตอนที่ 1
ขั้นที่ 5: ตรวจว่ามี NASM
Test-Path C:\apm-build\toolchain\nasm\nasm.exe
ต้องได้ True ถ้าได้ False ให้รัน pwsh -NoProfile -File scripts\00-fetch.ps1 -Only nasm NASM เป็นตัว assemble โค้ดภาษา assembly ของบาง delegate (ใน log ของผมเห็นสคริปต์ assemble ไฟล์ win64.asm ของ lib ffi)
ขั้นที่ 6: ตรวจว่า Visual Studio มี ATL/MFC
$vs = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -version '[17.0,18.0)' -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
Get-ChildItem "$vs\VC\Tools\MSVC\*\atlmfc" -Directory -Name
ต้องเห็นอย่างน้อยหนึ่งบรรทัด ซึ่งก็คือชื่อ atlmfc ถ้าไม่เห็นอะไรเลย ให้เปิด Visual Studio Installer กด Modify ที่ Visual Studio 2022 ตัวที่คุณลง (Build Tools หรือ edition อื่นก็ได้) แล้วติ๊ก ATL และ ATLMFC ตามตอนที่ 1 คำสั่งข้างบนใช้ vswhere หาโฟลเดอร์ติดตั้งให้ ไม่ผูกกับ path ของ BuildTools ถ้า vswhere หา Visual Studio 2022 ที่มี C++ x64 ไม่เจอ สคริปต์ build ก็หยุดด้วย [ERR] Visual Studio 2022 with C++ x64 tools not found เช่นกัน ให้กลับไปตอนที่ 1 สาเหตุที่ต้องใช้ ATL/MFC คือโปรแกรม Configure.exe ของ ImageMagick เป็นโปรแกรมแบบ MFC
(บนเครื่องผมมี MSVC หลายรุ่นอยู่ข้างกัน และ atlmfc อยู่ในรุ่น 14.44 ที่สคริปต์ใช้ ถ้าเครื่องคุณมีรุ่นเดียวก็จะเห็นบรรทัดเดียว)
ขั้นที่ 7: ตรวจที่ว่างบนดิสก์
(Get-PSDrive C).Free / 1GB
ผลคือตัวเลขจำนวนกิกะไบต์ที่ว่าง ควรมากกว่า 10 เครื่องผมมีว่างหลายร้อย GB เลยไม่ใช่ปัญหา
สคริปต์ทั้งไฟล์ และอ่านทีละท่อน
นี่คือ scripts\25-imagemagick.ps1 ทั้งไฟล์จากชุดที่โหลดมา
# 25-imagemagick.ps1 - build ImageMagick 7 (+ all delegate libs) from source with the official
# ImageMagick/Windows toolchain, then lay out headers/libs for the PHP imagick extension.
# Version comes from versions.json -> sources.imagemagick.version (an ImageMagick git tag).
param([switch]$SkipClone)
$ErrorActionPreference = 'Stop'
$Root = Split-Path $PSScriptRoot -Parent
. "$PSScriptRoot\lib.ps1"
$Tag = (Get-Content "$Root\versions.json" -Raw | ConvertFrom-Json).sources.imagemagick.version
$W = "$Root\src\imagemagick-windows"
$Dev = "$Root\build\im-dev"
$Log = "$Root\build\logs\imagemagick.log"
New-Item -ItemType Directory -Force "$Root\build\logs" | Out-Null
# 1. sources: ImageMagick at $Tag + the Configure/Dependencies versions that tag pins
if (-not $SkipClone) {
if (-not (Test-Path $W)) { git clone --quiet https://github.com/ImageMagick/Windows.git $W }
Push-Location $W
& "$env:ProgramFiles\Git\bin\bash.exe" -c "./clone-repositories.sh --imagemagick7 --commit $Tag" *> "$Root\build\logs\im-clone.log"
if ($LASTEXITCODE) { Pop-Location; throw "[ERR] clone failed (build\logs\im-clone.log)" }
Pop-Location
}
Enter-VsEnv
$env:Path = "$Root\toolchain\nasm;$env:Path"
# 2. Configure.exe (project targets v145/VS2026; this box has v143/VS2022)
Push-Location "$W\Configure"
# Windows Configure hardcodes a 64-bit channel mask on x64, which makes MagickCore headers C++-only
# (#error in magick-baseconfig.h). imagick is C -> use 32 like the Linux default.
$opt = 'src\Options.cpp'
$src = Get-Content $opt -Raw
$patched = $src -replace '(?s)(Options::channelMaskDepth\(\) const.*?if \(architecture != Architecture::x86\)\s*return\(L")64("\);)', '${1}32$2'
if ($patched -ne $src) { Set-Content $opt $patched -NoNewline -Encoding utf8; Write-Host '[OK] Configure patched: channel mask 32' }
elseif ($src -notmatch 'channelMaskDepth') { throw '[ERR] Options.cpp layout changed - re-check the channel mask patch' }
Invoke-Step 'IM Configure.exe build' { msbuild Configure.sln /m /t:Rebuild /p:Configuration=Release,Platform=x64 /p:PlatformToolset=v143 /v:minimal /nologo } $Log
Copy-Item Artifacts\Release\x64\bin\Configure.Release.x64.exe . -Force
# 3. generate IM7.Dynamic.x64.sln: VS2022 toolset, x64, DLL build, Q16 + HDRI (IM7 default)
Invoke-Step 'IM configure' { .\Configure.Release.x64.exe /noWizard /VS2022 /x64 /dynamic /Q16 /hdri } $Log
Pop-Location
# 4. build everything (ImageMagick + delegates: jpeg, png, webp, heif, tiff, freetype, xml, zlib ...)
Push-Location $W
Invoke-Step 'IM build' { msbuild IM7.Dynamic.x64.sln /m /t:Build /p:Configuration=Release,Platform=x64 /v:minimal /nologo } $Log
Pop-Location
# 5. dev layout for imagick's config.w32: <dir>\MagickCore\*.h, <dir>\MagickWand\*.h, <dir>\CORE_RL_*.lib
if (Test-Path $Dev) { Remove-Item $Dev -Recurse -Force }
New-Item -ItemType Directory -Force "$Dev\MagickCore", "$Dev\MagickWand" | Out-Null
Copy-Item "$W\ImageMagick\MagickCore\*.h" "$Dev\MagickCore"
Copy-Item "$W\ImageMagick\MagickWand\*.h" "$Dev\MagickWand"
Copy-Item "$W\Artifacts\lib\CORE_RL_Magick*_.lib" $Dev
Write-Host "[OK] ImageMagick $Tag -> $W\Artifacts\bin ; dev layout -> $Dev"
ท่อนที่ 1: ตัวแปร และสวิตช์ -SkipClone
$Tag อ่านจาก versions.json เหมือนทุกสคริปต์ในชุด (ตอนนี้คือ 7.1.2-34) $W คือ C:\apm-build\src\imagemagick-windows ที่เก็บ toolchain ทั้งก้อน $Dev คือ C:\apm-build\build\im-dev ปลายทางของไฟล์ที่ PHP จะใช้ $Log คือ C:\apm-build\build\logs\imagemagick.log
พารามิเตอร์ -SkipClone ข้ามขั้น clone ทั้งหมด ใช้ตอนที่ source อยู่ครบแล้วและต้องการ build ซ้ำเฉย ๆ ไม่ต้องรอเครือข่าย จุดที่ต่างจากสคริปต์ MariaDB ในตอนที่ 4 คือสคริปต์นี้ไม่ลบ imagemagick.log ทิ้งตอนเริ่ม log จะต่อท้ายไปเรื่อย ๆ ทุกรอบ เวลาไล่หา error ให้ดูที่ท้ายไฟล์เป็นหลัก
ท่อนที่ 2: clone ที่ tag ที่ต้องการ (ขั้น 1 ของสคริปต์)
ถ้ายังไม่มีโฟลเดอร์ $W สคริปต์ git clone ตัว toolchain ImageMagick/Windows มาก่อน จากนั้นเข้าโฟลเดอร์นั้นแล้วเรียก bash.exe ของ Git ให้รัน ./clone-repositories.sh --imagemagick7 --commit 7.1.2-34 สคริปต์ .sh ตัวนี้เป็นของทีม ImageMagick มันจะ clone ImageMagick เองแล้ว checkout ไปที่ tag ที่เราส่งให้ จากนั้น clone repo Configure กับ Dependencies และ repo ของ delegate แต่ละตัว แล้วปรับให้เป็นรุ่นที่ tag นั้นกำหนด (HOWTO บันทึกว่าเวอร์ชันของ Configure และ Dependencies ถูก pin ตาม tag อัตโนมัติ)
output ทั้งหมดไม่ขึ้นหน้าจอ เพราะ *> เปลี่ยนทางไปลง build\logs\im-clone.log ตัวอย่างบรรทัดจริงที่อยู่ในไฟล์นั้น
Cloning ImageMagick
HEAD is now at a0c4bf729 release
Cloning Configure
HEAD is now at 08ea96d Bump _WIN32_WINNT to Windows 10 to fix issues with the cairo build.
Cloning Dependencies
HEAD is now at ab03aca Bump actions/create-github-app-token from 3.2.0 to 3.3.0 (#47)
Cloning aom
HEAD is now at 949b208 Move part of the header to a separate file to reduce the binary size.
Cloning fontconfig
HEAD is now at 943048d Updated fontconfig to 2.18.3
ตัวเลข a0c4bf729 คือ commit ของ ImageMagick ที่ tag 7.1.2-34 ชี้ไป และรหัสเดียวกันนี้จะโผล่ในข้อความรุ่นของ magick -version ท้ายตอน (a0c4bf729:20261014) เป็นการยืนยันว่าไบนารีที่ได้มาจาก source ที่เราสั่ง ไม่ใช่ของอื่น
ในไฟล์เดียวกันผมเห็นบรรทัด grep: ImageMagick/.github/build/windows/download-dependencies.sh: No such file or directory หลังขั้น clone Configure บรรทัดนี้ไม่ได้หยุดสคริปต์และ build ของผมผ่านจนจบ ผมไม่ได้ตามต่อว่ามันมีผลกับอะไร เลยขอบอกแค่ว่ามันปรากฏในล็อกของผมแต่ไม่ได้ทำให้ล้ม ล็อก clone ของผมมีบรรทัด Cloning ทั้งหมด 45 บรรทัด
ถ้าขั้น clone ล้ม ตัวสคริปต์เช็ก $LASTEXITCODE แล้ว throw [ERR] clone failed (build\logs\im-clone.log) ให้เปิดไฟล์นั้นดูท้ายไฟล์ ส่วนมากสาเหตุคือเครือข่ายหลุดกลางทาง รันสคริปต์ซ้ำได้เลย ผมรันซ้ำแล้วเห็น Already up to date. ในล็อก แปลว่า repo ที่ clone เสร็จแล้วไม่ถูกโหลดใหม่
ท่อนที่ 3: เตรียม environment
Enter-VsEnv โหลด MSVC เข้า PowerShell ตัวนี้ (เหมือนตอนที่ 4) แล้วเพิ่ม toolchain\nasm ไว้หน้าสุดของ PATH ให้ MSBuild เรียก nasm.exe เจอ
ท่อนที่ 4: แพตช์ channel mask (ขั้น 2 ของสคริปต์)
นี่คือส่วนที่สำคัญที่สุดของตอนนี้ ผมแยกอธิบายในหัวข้อถัดไป
ท่อนที่ 5: build Configure.exe ด้วย toolset v143
Configure.exe คือโปรแกรมของ ImageMagick ที่อ่านตัวเลือกแล้วสร้าง solution (.sln) สำหรับ build ตัวจริง ตัวโปรแกรมเองต้อง build ก่อน ด้วยคำสั่ง
msbuild Configure.sln /m /t:Rebuild /p:Configuration=Release,Platform=x64 /p:PlatformToolset=v143 /v:minimal /nologo
| ตัวเลือก | ความหมาย |
|---|---|
/m |
build หลาย project พร้อมกันตามจำนวน core |
/t:Rebuild |
build ใหม่ทั้งหมดทุกรอบ ไม่ใช้ผลเก่า (เพราะเพิ่งแก้ source ของมัน) |
/p:Configuration=Release,Platform=x64 |
ชนิดและสถาปัตยกรรมที่ build |
/p:PlatformToolset=v143 |
บังคับใช้คอมไพเลอร์ MSVC v143 ของ VS 2022 |
/v:minimal /nologo |
ลดข้อความที่พิมพ์ออกมา |
ที่ต้องบังคับ v143 เพราะ project ของ Configure ตั้ง toolset ไว้เป็น v145 ซึ่งเป็นของ Visual Studio 2026 (คอมเมนต์ในสคริปต์เขียนไว้เหมือนกัน) เครื่องเราเป็น VS 2022 เลยไม่มี v145 ให้ ถ้าไม่ใส่ตัวเลือกนี้ build จะล้มเพราะหา toolset ไม่เจอ
หลัง build เสร็จ ตัวโปรแกรมอยู่ที่ Configure\Artifacts\Release\x64\bin\Configure.Release.x64.exe สคริปต์ Copy-Item มันมาไว้ในโฟลเดอร์ Configure เพื่อให้เรียกด้วยชื่อสั้น ๆ ได้
ท่อนที่ 6: ให้ Configure.exe สร้างไฟล์ .sln (ขั้น 3 ของสคริปต์)
.\Configure.Release.x64.exe /noWizard /VS2022 /x64 /dynamic /Q16 /hdri
ผมใช้ .\ นำหน้าเพราะบางเครื่องตั้ง NoDefaultCurrentDirectoryInExePath=1 ทำให้ cmd และ PowerShell ไม่ค้นหาไฟล์ในโฟลเดอร์ปัจจุบัน (เจอเรื่องเดียวกันนี้ตอน build PHP) ตัวเลือกแต่ละตัวมีความหมายดังนี้
| ตัวเลือก | ความหมาย |
|---|---|
/noWizard |
ไม่เปิดหน้าต่างให้ติ๊กเลือก รับค่าจากบรรทัดคำสั่งอย่างเดียว (สำคัญ ไม่งั้นสคริปต์จะค้างรอคน) |
/VS2022 |
สร้าง solution สำหรับ Visual Studio 2022 |
/x64 |
สถาปัตยกรรม 64 บิต |
/dynamic |
build เป็น DLL (ชุดไฟล์ CORE_RL_*.dll) ไม่ใช่ไลบรารีแบบ static |
/Q16 |
ความลึกสี quantum 16 บิตต่อช่อง (ค่ามาตรฐานของ ImageMagick 7) |
/hdri |
เปิด HDRI รองรับค่าสีนอกช่วงปกติ (ค่ามาตรฐานของ ImageMagick 7) |
ผลคือไฟล์ IM7.Dynamic.x64.sln ถูกสร้างที่รากของ src\imagemagick-windows ซึ่งเป็นไฟล์เดียวที่ขั้นถัดไปต้องการ
ท่อนที่ 7: build ทั้งหมด (ขั้น 4 ของสคริปต์)
msbuild IM7.Dynamic.x64.sln /m /t:Build /p:Configuration=Release,Platform=x64 /v:minimal /nologo
ตรงนี้คือก้อนที่กินเวลาเกือบทั้งหมด มันคอมไพล์ ImageMagick และ delegate library ทั้งหมดตามที่ ImageMagick/Windows กำหนด สังเกตว่าคราวนี้ใช้ /t:Build ไม่ใช่ Rebuild เลยทำต่อจากของเดิมได้ รอบรันซ้ำเลยเหลือ 3.3 นาที
บรรทัดที่เห็นใน imagemagick.log ระหว่างทาง (path ผมแก้เป็น C:\apm-build)
Assembling C:\apm-build\src\imagemagick-windows\Dependencies\Dependencies\ffi\src\x86\win64.asm...
aom_codec.c
APP_magick.vcxproj -> C:\apm-build\src\imagemagick-windows\Artifacts\bin\magick.exe
APP_compare.vcxproj -> C:\apm-build\src\imagemagick-windows\Artifacts\bin\compare.exe
solution นี้ build โปรแกรม fuzz (ชื่อขึ้นต้น FUZZ_) และเครื่องมืออื่นของ ImageMagick ไปด้วย ซึ่งเราไม่ได้ใช้ แต่ปล่อยไว้ตามต้นฉบับ ไม่ได้แก้ solution
ท่อนที่ 8: จัดโฟลเดอร์ im-dev (ขั้น 5 ของสคริปต์)
สคริปต์ลบ build\im-dev ทิ้งถ้ามี แล้วสร้างใหม่ ข้างในมีสามส่วน ไฟล์ header ของ MagickCore, ไฟล์ header ของ MagickWand และไลบรารีนำเข้า (import library) สามตัวชื่อ CORE_RL_Magick*_.lib เหตุผลคือไฟล์ตั้งค่าของ imagick (config.w32) มองหาของในโครงนี้พอดี: <โฟลเดอร์>\MagickCore\*.h, <โฟลเดอร์>\MagickWand\*.h และ <โฟลเดอร์>\CORE_RL_*.lib ตอนที่ 6 เราจะส่งโฟลเดอร์นี้ให้ผ่าน --with-imagick=shared,build\im-dev
บรรทัดสุดท้ายของสคริปต์พิมพ์ [OK] ImageMagick 7.1.2-34 -> ...\Artifacts\bin ; dev layout -> ...\build\im-dev
แพตช์เดียวที่ต้องแก้: channel mask 64 เป็น 32
ผมเจอ error ตัวนี้จริงตอน build imagick รอบแรก และสาเหตุฝังอยู่ใน ImageMagick ไม่ใช่ใน PHP เลยต้องแก้ตั้งแต่ขั้น build ImageMagick
อาการ
ตอนที่ 6 ที่ build extension imagick จะขึ้น error นี้
ImageMagick was build with a 64 channel bit mask and that requires a C++ compiler
มันมาจาก header MagickCore\magick-baseconfig.h ของ ImageMagick เอง ผมเปิดไฟล์จริงดูแล้ว บรรทัด 266 ถึง 270 เขียนไว้ว่า
#if MAGICKCORE_CHANNEL_MASK_DEPTH == 64
# if !defined(__cplusplus) && !defined(c_plusplus)
# error ImageMagick was build with a 64 channel bit mask and that requires a C++ compiler
# endif
#endif
สาเหตุ
ค่า MAGICKCORE_CHANNEL_MASK_DEPTH ถูกกำหนดตอนรัน Configure.exe โดยบน x64 โปรแกรมนี้เลือก 64 เองเสมอ ทำให้ header ที่ได้ใช้กับโค้ดภาษา C ไม่ได้ ส่วน imagick เขียนด้วยภาษา C เลยชนกำแพงนี้ ที่ Linux ค่าเริ่มต้นเป็น 32 ซึ่งตรงกับเครื่อง production ของผมด้วย เลยเลือกแก้ให้เป็น 32
วิธีแก้ในสคริปต์
ค่านี้ถูกคืนจากฟังก์ชัน Options::channelMaskDepth() ในไฟล์ Configure\src\Options.cpp สคริปต์แก้ไฟล์นั้นก่อน build Configure ด้วย regex หนึ่งบรรทัด
$patched = $src -replace '(?s)(Options::channelMaskDepth\(\) const.*?if \(architecture != Architecture::x86\)\s*return\(L")64("\);)', '${1}32$2'
อ่านทีละท่อนได้ดังนี้
(?s)ให้จุด.จับตัวขึ้นบรรทัดใหม่ด้วย เพราะฟังก์ชันกินหลายบรรทัด(Options::channelMaskDepth\(\) const.*?if \(architecture != Architecture::x86\)\s*return\(L")จับตั้งแต่หัวฟังก์ชันไปจนถึงข้อความreturn(L"ใต้เงื่อนไข "ไม่ใช่ x86" (กลุ่มที่ 1) ตัว.*?จับแบบสั้นที่สุดเพื่อไม่ลามไปฟังก์ชันอื่น64คือเลขที่จะเปลี่ยน("\);)กลุ่มที่ 2 คือ");ปิดท้าย- ผลลัพธ์
${1}32$2ประกอบกลับเป็นกลุ่ม 1 +32+ กลุ่ม 2
หลังแก้ ฟังก์ชันในไฟล์ของผมอ่านได้ดังนี้ (ทั้งสองสาขาคืน 32 เพราะสาขา x86 เดิมเป็น 32 อยู่แล้ว)
const wstring Options::channelMaskDepth() const
{
if (!isImageMagick7)
return(L"");
if (architecture != Architecture::x86)
return(L"32");
else
return(L"32");
}
สคริปต์มีทางออกสองทางที่กันความผิดพลาด ถ้าแก้ได้จะพิมพ์ [OK] Configure patched: channel mask 32 ถ้าไม่เปลี่ยนอะไร (แพตช์ไว้แล้วจากรอบก่อน) จะเงียบ และถ้าในไฟล์ไม่มีคำว่า channelMaskDepth เลย (แปลว่าทีม ImageMagick เปลี่ยนโครงไฟล์) สคริปต์จะ throw [ERR] Options.cpp layout changed - re-check the channel mask patch แทนที่จะปล่อยให้ build ต่อไปด้วยค่า 64 แล้วไปล้มทีหลังตอน build PHP
ที่ผมเลือก 32 เพราะต้องการให้ผลของภาพที่ประมวลผลผ่าน imagick ตรงกับเครื่อง production ซึ่งใช้ค่านี้ ผมไม่ได้ทดลองกรณี 64 บิต ในซีรีส์นี้ใช้ 32 เท่านั้น
รันจริงทีละขั้น
ขั้นที่ 1: รันสคริปต์
ที่ terminal เดิม (PowerShell 7 แบบ user ปกติ ใน C:\apm-build) สั่ง
pwsh -NoProfile -File scripts\25-imagemagick.ps1
ผลทันทีคือหน้าจอเงียบไปสักพัก เพราะกำลัง clone และ output ลงไฟล์ ไม่มีข้อความขึ้นจนกว่าจะผ่านขั้น clone ถ้าคุณใช้ build.cmd ล้มที่ขั้นนี้ ใช้ build.cmd -From imagemagick เพื่อรันต่อ (จะต่อด้วยขั้น php)
ขั้นที่ 2: เปิด terminal ตัวที่สองดูความคืบหน้าของ clone (ทางเลือก)
Get-Content C:\apm-build\build\logs\im-clone.log -Tail 5 -Wait
จะเห็นบรรทัด Cloning ... วิ่งเรื่อย ๆ ทีละ repo เมื่อหยุดวิ่งแล้ว กด Ctrl+C เพื่อเลิกดู (ไม่กระทบสคริปต์หลัก)
ขั้นที่ 3: ดูว่าเริ่มขั้น build Configure.exe
เมื่อ clone จบ ที่หน้าต่างแรกจะขึ้น (ครั้งแรกเท่านั้น จะมีบรรทัดแพตช์นำหน้า)
[OK] Configure patched: channel mask 32
[..] IM Configure.exe build
[OK] IM Configure.exe build
[..] IM configure
[OK] IM configure
[..] IM build
ระหว่าง [..] IM build กับ [OK] IM build จะเงียบนานที่สุด เปิดสังเกตการทำงานจริงด้วย
Get-Content C:\apm-build\build\logs\imagemagick.log -Tail 5 -Wait
ขั้นที่ 4: รอ build ทั้ง solution
ใช้เวลาเป็นส่วนใหญ่ของ 40-60 นาที CPU จะเต็มทุก core ห้ามปิดหน้าต่าง ห้ามให้เครื่อง sleep ถ้าหยุดกลางคันก็รันซ้ำขั้นที่ 1 ได้เลย (ใช้ -SkipClone ได้ถ้า clone จบแล้ว) MSBuild จะทำต่อจากของเดิม
ขั้นที่ 5: ดูบรรทัดปิดท้ายของสคริปต์
[OK] IM build
[OK] ImageMagick 7.1.2-34 -> C:\apm-build\src\imagemagick-windows\Artifacts\bin ; dev layout -> C:\apm-build\build\im-dev
ขั้นที่ 6: ตรวจว่า magick.exe ทำงาน
C:\apm-build\src\imagemagick-windows\Artifacts\bin\magick.exe -version
ผลที่ควรเห็น (นี่คือผลจริงจากเครื่องผม)
Version: ImageMagick 7.1.2-34 Q16-HDRI x64 a0c4bf729:20261014 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/license/
Features: Cipher DPC HDRI Modules OpenCL OpenMP(2.0)
Delegates (built-in): bzlib cairo freetype gslib heic jng jp2 jpeg jxl lcms lqr lzma openexr pangocairo png ps raqm raw rsvg tiff webp xml zip zlib zstd
Compiler: Visual Studio 2022 (194435217)
อ่านให้ออกสามจุด Q16-HDRI x64 ตรงกับตัวเลือก /Q16 /hdri /x64 ที่ส่งให้ Configure, a0c4bf729 ตรงกับ commit ที่ clone ไว้ และรายการ Delegates (built-in) คือไลบรารีที่ถูกฝังเข้ามาทั้งหมด
ขั้นที่ 7: ตรวจว่า channel mask เป็น 32
Select-String -Path C:\apm-build\src\imagemagick-windows\ImageMagick\MagickCore\magick-baseconfig.h -Pattern 'define MAGICKCORE_CHANNEL_MASK_DEPTH'
ผลที่ควรเห็น (ท้ายบรรทัดเป็นเลข 32 ส่วนหน้าบรรทัดจะมีชื่อไฟล์และเลขบรรทัดนำหน้า)
#define MAGICKCORE_CHANNEL_MASK_DEPTH 32
ถ้าได้ 64 แปลว่าแพตช์ไม่เข้า ให้ไปหัวข้อ "ถ้าพังตรงนี้"
ขั้นที่ 8: ตรวจโฟลเดอร์ im-dev
Get-ChildItem C:\apm-build\build\im-dev -Name
ผลที่ควรเห็น
MagickCore
MagickWand
CORE_RL_Magick++_.lib
CORE_RL_MagickCore_.lib
CORE_RL_MagickWand_.lib
(ลำดับการแสดงผลอาจต่าง แต่ต้องมีครบห้ารายการนี้) โฟลเดอร์ทั้งหมดบนเครื่องผมหนักราว 2.7 MB
ขั้นที่ 9: ลองแปลงภาพจริงหนึ่งไฟล์
ขั้นนี้เป็นการทดสอบที่ผมทำเองเพิ่มจากสคริปต์ เพื่อยืนยันว่า delegate ทำงานจริง ไม่ใช่แค่ถูกลิสต์ไว้ สร้างภาพสีล้วนขนาด 320x200 แล้วบันทึกเป็น webp
C:\apm-build\src\imagemagick-windows\Artifacts\bin\magick.exe -size 320x200 xc:'#3366cc' $env:TEMP\apm-test.webp
ไม่มี output เมื่อสำเร็จ ตรวจว่ามีไฟล์ด้วย (Get-Item $env:TEMP\apm-test.webp).Length ผลของผมได้ 240 ไบต์ ลองเปลี่ยนนามสกุลเป็น .avif .png .jpg ได้เช่นกัน ผมได้ 318, 315 และ 1038 ไบต์ตามลำดับ (ขนาดนี้ขึ้นกับรุ่นของ encoder ถ้าของคุณต่างเล็กน้อยไม่ใช่ปัญหา ขอแค่ไฟล์เกิดขึ้นและไม่มีข้อความ error) ลบไฟล์ทดสอบทิ้งเมื่อเสร็จด้วย Remove-Item $env:TEMP\apm-test.*
ข้อจำกัดที่ต้องรู้: เขียนไฟล์ HEIC ไม่ได้
ลองเขียน HEIC ด้วยวิธีเดียวกับขั้นที่ 9
C:\apm-build\src\imagemagick-windows\Artifacts\bin\magick.exe -size 320x200 xc:'#3366cc' $env:TEMP\apm-test.heic
ผมได้ข้อความนี้ (ข้อความจริง)
magick.exe: no encode delegate for this image format `HEIC' @ warning/constitute.c/WriteImage/1473.
magick.exe: no encode delegate for this image format `HEIC' @ error/constitute.c/WriteImage/1482.
ตรวจรายชื่อ format ที่รองรับ
C:\apm-build\src\imagemagick-windows\Artifacts\bin\magick.exe -list format | Select-String 'HEIC'
AVIF HEIC rw+ AV1 Image File Format (1.23.6)
HEIC HEIC r-- High Efficiency Image Format (1.23.6)
อ่านคอลัมน์สิทธิ์: r-- ของ HEIC แปลว่าอ่านได้อย่างเดียว เขียนไม่ได้ ส่วน rw+ ของ AVIF แปลว่าอ่านและเขียนได้ ตามที่ HOWTO บันทึกไว้ สาเหตุคือ encoder ของ HEIC (x265) ไม่ถูกรวมเข้ามาด้วยเหตุผลด้านไลเซนส์ ภาพ HEIC จากมือถือยังอ่านและแปลงเป็น jpeg หรือ webp ได้ปกติ แต่เขียนออกเป็น HEIC ไม่ได้ ส่วน webp, avif, png, jpeg อ่านและเขียนได้
webp, avif, png, jpeg
ผมทดสอบเขียนครบสี่ชนิดผ่าน magick.exe ด้วยภาพ 320x200 ได้ไฟล์ทุกชนิด ใช้เป็นปลายทางของระบบย่อรูปได้
heic
รับภาพจากมือถือเข้ามาได้ แต่สั่งบันทึกเป็น heic ไม่ได้ ต้องแปลงเป็นชนิดอื่นก่อนเสมอ
ถ้าพังตรงนี้
ตารางนี้รวมอาการที่ HOWTO บันทึกไว้จากการ build จริง ส่วนแถวท้ายสุดสองแถวระบุว่าเป็นเหตุที่อ่านได้จากสคริปต์ ไม่ใช่ที่ผมเจอเอง
| อาการ | สาเหตุ | วิธีแก้ | ที่มา |
|---|---|---|---|
ImageMagick was build with a 64 channel bit mask and that requires a C++ compiler (ตอน build imagick ตอนที่ 6) |
Configure ตั้ง mask 64 บน x64 | ให้แพตช์ใน Options.cpp ทำงาน (ขั้นที่ 7 ข้างบนต้องได้ 32) แล้ว build ImageMagick ใหม่ |
เจอจริง |
| Configure build ไม่ผ่านเพราะหา toolset v145 ไม่เจอ | project ตั้งไว้สำหรับ VS 2026 | ใส่ /p:PlatformToolset=v143 และสั่ง Configure ด้วย /VS2022 (สคริปต์ทำให้แล้ว) |
เจอจริง |
Class "Imagick" not found ตอนรัน PHP |
ไม่มี extension = imagick ใน php.ini |
ใส่ในไฟล์ template แล้ว ถ้า deploy ไปก่อนหน้านี้ให้รัน deploy.cmd -ResetConfig (ตอนที่ 7) |
เจอจริง |
[ERR] Options.cpp layout changed - re-check the channel mask patch |
ทีม ImageMagick เปลี่ยนโครงไฟล์ ตัว regex หาฟังก์ชันไม่เจอ | เปิด Configure\src\Options.cpp ดูฟังก์ชันที่คืนค่า channel mask ใหม่ แล้วปรับ regex ในสคริปต์ |
ข้อความมาจากสคริปต์ ผมไม่ได้เจอเอง |
[ERR] clone failed (build\logs\im-clone.log) |
เครือข่ายหลุด หรือ bash.exe ของ Git ไม่อยู่ที่ path ที่สคริปต์เรียก |
ดูท้าย im-clone.log แก้เครือข่ายหรือติดตั้ง Git ให้ตรง path แล้วรันซ้ำ |
ข้อความมาจากสคริปต์ ผมไม่ได้เจอเอง |
Configure.sln build ไม่ผ่านเกี่ยวกับ ATL/MFC |
component ATL หรือ ATLMFC ไม่ครบ | Visual Studio Installer, Modify, ติ๊ก ATL และ ATLMFC | HOWTO ระบุว่า Configure เป็นโปรแกรม MFC (ผมไม่ได้เก็บข้อความ error จริง) |
ขั้น IM build ล้มคือจุดที่ข้อความ error หายไปในล็อกยาวสี่พันบรรทัด สคริปต์พิมพ์ 30 บรรทัดสุดท้ายให้ แต่บรรทัด error จริงมักอยู่เหนือขึ้นไป ใช้คำสั่งนี้หาแบบที่ MSBuild เขียน
Select-String -Path C:\apm-build\build\logs\imagemagick.log -Pattern ': error ' | Select-Object -Last 10
ถ้าคุณเคยแก้ PATH ไว้ให้ perl ของ Git for Windows (ตัว cygwin) มาก่อน ให้เอาออกก่อน build ทั้งชุด toolchain ต้องการ Strawberry Perl ใน toolchain\strawberry เท่านั้น เรื่องนี้ผมเจอจริงตอน build OpenSSL ในชุดเดียวกัน
เช็กลิสต์ก่อนไปตอนที่ 6
- สคริปต์ปิดท้ายด้วย
[OK] ImageMagick 7.1.2-34 -> ... magick.exe -versionแสดงImageMagick 7.1.2-34 Q16-HDRI x64และ commita0c4bf729- บรรทัด
MAGICKCORE_CHANNEL_MASK_DEPTHในmagick-baseconfig.hเป็น32 C:\apm-build\build\im-devมีMagickCore,MagickWandและไฟล์CORE_RL_*.libสามตัว- เขียนไฟล์ webp, avif, png, jpg ด้วย
magick.exeได้ (HEIC เขียนไม่ได้ตามที่คาดไว้)
ใครอยากได้ APM ไปใช้เลยโดยไม่ต้องคอมไพล์ ผมปล่อยตัวที่ build เสร็จแล้วไว้ที่ github.com/ChonLaWan/APM-Server โหลด APM-1.0.0-win64.zip (ราว 140 MB) จากหน้า Releases เทียบ sha256 กับไฟล์ .sha256 ที่แนบไว้ แตกไว้ที่ไหนก็ได้ แล้วเปิด manager\APMManager.exe ตัว Manager จะเลือกพอร์ต เขียน config ออก cert และสร้างฐานข้อมูลให้เอง มีปุ่ม Check for updates ที่โหลดรุ่นใหม่จาก Releases มาตรวจ sha256 แล้วแทน binary ให้ โดยไม่แตะ config ฐานข้อมูล และเว็บของเรา
สารบัญ · ตอนก่อนหน้า: ตอนที่ 4 คอมไพล์ MariaDB · ตอนถัดไป: ตอนที่ 6 คอมไพล์ PHP 8.4
ตอนถัดไปคือ PHP เอง ผมจะเอา build\im-dev กับ DLL จากตอนนี้ไปประกอบเป็น extension imagick ให้ครบพร้อม extension อีกกว่าห้าสิบตัว ส่วนเรื่องที่ผมยังไม่ได้ทดลองในตอนนี้ เช่นการเปิด encoder ของ HEIC ด้วยตัวเอง ผมยังไม่มีผลทดสอบที่ยืนยันได้ เดี๋ยวกลับมาแก้เพิ่มให้ภายหลังครับ
อยากให้เราทำให้ไหม?
ให้เราช่วยติดตั้ง ตั้งค่า ย้ายระบบ หรือแก้ปัญหาเซิร์ฟเวอร์ เพื่อให้คุณมีเวลาไปทำงานที่สำคัญกว่า
เคยเจองานแบบนี้ไหม? ติดตรงไหน?
มาแลกวิธีกันต่อในบอร์ด LinuxThai



ความคิดเห็น 0
ยังไม่มีความคิดเห็น — เป็นคนแรกเลย