Build APM บน Windows ตอนที่ 2: ดึง source และ lib ด้วย vcpkg
ก่อนจะคอมไพล์อะไรได้ ต้องมี source ที่ตรวจแล้วว่าไม่ใช่ไฟล์ปลอม กับ lib ที่ Apache ต้องใช้ครบทุกตัว สองงานนี้ใช้เวลารวมเกือบชั่วโมงในรอบแรก แต่ทำครั้งเดียว รอบถัดไปได้ของเดิมจาก cache เกือบทั้งหมด
พอดีผมต้องเขียนขั้นตอนนี้ให้คนที่ไม่เคยคอมไพล์อะไรเลยทำตามได้ เลยเปิดสคริปต์ทั้งสองตัวขึ้นมาอ่านใหม่ทีละบรรทัด แล้วเอาทุกคำสั่งในบทความนี้ไปตรวจกับเครื่องที่ผม build ไว้แล้วอีกรอบ ตอนที่ 2 นี้เป็นตอนที่ผมอยากให้คุณอ่านช้า ๆ ที่สุด เพราะเป็นตอนที่ตัดสินว่าของที่จะถูกคอมไพล์เป็น web server ของคุณมาจากไหน และเชื่อถือได้แค่ไหน ถ้า source ที่ดาวน์โหลดมาถูกสลับไส้ ต่อให้ขั้นต่อ ๆ ไปทำถูกทุกบรรทัด ผลที่ได้ก็คือ Apache ที่มีของแถมโดยที่เราไม่รู้
ตอนนี้ทำสองสคริปต์ คือ 00-fetch.ps1 ดาวน์โหลดและตรวจ hash ของ source กับเครื่องมือทั้งหมด และ 10-deps-vcpkg.ps1 ให้ vcpkg คอมไพล์ lib ที่ Apache ต้องใช้ (OpenSSL, PCRE2, zlib, nghttp2, brotli, expat, libxml2, jansson, curl) จาก source ด้วย MSVC ถ้ายังไม่ได้อ่านตอนที่ 1 ที่ติดตั้ง Build Tools กับแตกชุด kit ไว้ที่ C:\apm-build ให้กลับไปทำก่อน เพราะตอนนี้ถือว่าเครื่องมือครบแล้ว
PHP ออกแพตช์ช่องโหว่ RCE ระดับวิกฤตสองตัวเมื่อ 2026-10-21 (รายละเอียดอยู่ใน บทความข่าว php2shell) ผมเลย build stack ของตัวเองให้เปลี่ยนเลขเวอร์ชันในไฟล์ versions.json ไฟล์เดียวแล้ว build ใหม่ได้ในวันเดียวกับที่ upstream ปล่อย ตอนที่ 2 คือส่วนที่ทำให้ข้อนั้นเป็นจริง เพราะ hash ของ source ทุกตัวถูกตรวจก่อนใช้
1. เตรียมตัว: เช็กว่าตอนที่ 1 เสร็จจริง
ทุกขั้นในตอนนี้และตอนต่อ ๆ ไปรันด้วย PowerShell 7 (pwsh) ในสิทธิ์ user ปกติ ไม่ต้องเปิดเป็น Administrator สคริปต์ build โหลด environment ของ MSVC ให้เอง เลยไม่ต้องเปิด Developer Prompt ส่วนข้อ 1 นี้เป็นการเช็กก่อนลงมือ ทำทีละข้อตามลำดับ
ขั้นที่ 1.1 เปิด pwsh
ที่ไหน: กด Start พิมพ์ pwsh แล้วเปิด PowerShell 7 ธรรมดา (ไม่ใช่ Run as administrator) หัวหน้าต่างควรเขียนว่า PowerShell 7 ไม่ใช่ Windows PowerShell
$PSVersionTable.PSVersion.ToString()
ควรเห็นเลขรุ่น 7.5 ขึ้นไป (เครื่องผมได้ 7.6.7) ถ้าได้ 5.1 แปลว่าเปิดผิดตัว สคริปต์ 00-fetch.ps1 ใช้ ConvertFrom-Json -AsHashtable ซึ่งมีแค่ใน PowerShell 6 ขึ้นไป รัน 5.1 จะล้มทันที
ขั้นที่ 1.2 เข้าโฟลเดอร์ของ kit
Set-Location C:\apm-build
Get-ChildItem -Name
ควรเห็นรายการนี้ (ลำดับอาจต่างเล็กน้อย)
deps
ports-overlay
scripts
templates
tools
.gitignore
build.cmd
deploy.cmd
README.txt
versions.json
versions.lock.json
ถ้าไม่เห็น build.cmd ตรงนี้ แปลว่าแตก zip ซ้อนโฟลเดอร์ (ได้ C:\apm-build\apm-build-kit\build.cmd) ให้ย้ายทุกอย่างขึ้นมาหนึ่งชั้นตามที่ตอนที่ 1 บอกไว้ ก่อนไปต่อ
ขั้นที่ 1.3 เช็กว่าเครื่องมือหลักตอบ
git --version; cmake --version | Select-Object -First 1; ninja --version; pwsh --version
git version 2.54.0.windows.1
cmake version 4.1.2
1.13.1
PowerShell 7.6.1
เลขรุ่นของคุณอาจใหม่กว่านี้ได้ ขอแค่ทุกตัวตอบกลับมา ถ้าตัวไหนขึ้น is not recognized ให้เปิด pwsh ใหม่ (PATH เพิ่งถูกเพิ่มหลัง winget) แล้วถ้ายังไม่ได้ให้กลับไปตอนที่ 1
ขั้นที่ 1.4 เช็กพื้นที่ดิสก์
[math]::Round((Get-PSDrive C).Free / 1GB, 1)
ต้องได้เลขไม่ต่ำกว่า 60 (หน่วย GB) เพราะ build ทั้งซีรีส์กินที่ประมาณ 45 GB ตอนที่ 2 ใช้ไม่มาก แต่ถ้าดิสก์เต็มกลางทางตอนที่ 5 หรือ 6 จะเสียเวลากว่าตอนนี้เยอะ
2. 00-fetch.ps1: ดาวน์โหลดแล้วตรวจ hash ก่อนแตกไฟล์
สคริปต์ตัวนี้ทำหน้าที่เดียวคือ อ่าน versions.json แล้วดึงทุกรายการที่มี url ลงโฟลเดอร์ downloads\ ตรวจ sha256 แล้วแตกไฟล์ไปไว้ใน toolchain\ (เครื่องมือ) หรือ src\ (source) นี่คือตัวสคริปต์เต็ม อ่านมันก่อนสักรอบแล้วค่อยดูคำอธิบายทีละช่วงข้างล่าง
# 00-fetch.ps1 - download + verify + extract everything pinned in versions.json
# Usage: pwsh scripts\00-fetch.ps1 [-Only php,httpd] [-Force]
param([string[]]$Only, [switch]$Force)
$ErrorActionPreference = 'Stop'
# `pwsh -File ... -Only php,httpd` passes ONE string "php,httpd" (no array parsing in -File mode)
$Only = @($Only | ForEach-Object { $_ -split ',' } | ForEach-Object { $_.Trim() } | Where-Object { $_ })
$Root = Split-Path $PSScriptRoot -Parent
$V = Get-Content "$Root\versions.json" -Raw | ConvertFrom-Json
$LockFile = "$Root\versions.lock.json"
$Lock = if (Test-Path $LockFile) { Get-Content $LockFile -Raw | ConvertFrom-Json -AsHashtable } else { @{} }
$Dl = "$Root\downloads"; New-Item -ItemType Directory -Force $Dl, "$Root\src" | Out-Null
function Get-One($name, $item, $destDir, $strip) {
if ($Only -and $name -notin $Only) { return }
if (-not $item.url) { return } # git-based sources (imagemagick) are fetched by their own build script
$file = Join-Path $Dl ([IO.Path]::GetFileName(([uri]$item.url).AbsolutePath))
if (-not (Test-Path $file) -or $Force) {
Write-Host "[GET] $name $($item.version)"
curl.exe -fsSL --retry 3 -o "$file.part" $item.url
if ($LASTEXITCODE) { throw "download failed: $($item.url)" }
Move-Item -Force "$file.part" $file
}
$sha = (Get-FileHash $file -Algorithm SHA256).Hash.ToLower()
$want = if ($item.sha256) { $item.sha256 } elseif ($Lock[$name]) { $Lock[$name] } else { $null }
if ($want -and $sha -ne $want) { throw "[ERR] sha256 mismatch $name`n got $sha`n want $want" }
if ($item.sha1) {
$s1 = (Get-FileHash $file -Algorithm SHA1).Hash.ToLower()
if ($s1 -ne $item.sha1) { throw "[ERR] sha1 mismatch $name" }
}
if (-not $want) { Write-Host "[TOFU] $name sha256=$sha" }
$Lock[$name] = $sha
if ((Test-Path $destDir) -and -not $Force) { Write-Host "[OK] $name (already extracted)"; return }
if (Test-Path $destDir) { Remove-Item $destDir -Recurse -Force }
New-Item -ItemType Directory -Force $destDir | Out-Null
tar.exe -xf $file -C $destDir --strip-components=$strip
if ($LASTEXITCODE) { throw "extract failed: $file" }
Write-Host "[OK] $name -> $destDir"
}
foreach ($p in $V.toolchain.PSObject.Properties) {
Get-One $p.Name $p.Value (Join-Path $Root $p.Value.dest) $p.Value.strip
}
foreach ($p in $V.sources.PSObject.Properties) {
Get-One $p.Name $p.Value (Join-Path "$Root\src" "$($p.Name)-$($p.Value.version)") 1
}
$Lock | ConvertTo-Json | Set-Content $LockFile -Encoding utf8
ไฟล์ versions.json ที่สคริปต์อ่าน
ผมย่อ hash ให้สั้นลงเพื่อให้อ่านง่าย ไฟล์จริงในชุด kit มี hash เต็ม 64 ตัวอักษร
{
"apm_version": "1.0.0",
"toolchain": {
"php-sdk": { "version": "2.8.4", "url": "https://github.com/php/php-sdk-binary-tools/archive/refs/tags/php-sdk-2.8.4.zip", "sha256": null, "dest": "toolchain/php-sdk", "strip": 1 },
"nasm": { "version": "3.01", "url": "https://www.nasm.us/pub/nasm/releasebuilds/3.01/win64/nasm-3.01-win64.zip", "sha256": null, "dest": "toolchain/nasm", "strip": 1 }
},
"sources": {
"php": { "version": "8.4.27", "url": "https://www.php.net/distributions/php-8.4.27.tar.xz", "sha256": "dcf93923b0e38e0d…" },
"httpd": { "version": "2.4.69", "url": "https://downloads.apache.org/httpd/httpd-2.4.69.tar.bz2", "sha256": "c5e6ebc66e349b87…" },
"mod_fcgid": { "version": "2.3.9", "url": "https://archive.apache.org/dist/httpd/mod_fcgid/mod_fcgid-2.3.9.tar.bz2", "sha256": null, "sha1": "f0b6d87dfcfe18b3…" },
"imagemagick": { "version": "7.1.2-34", "url": null, "sha256": null }
}
}
ในไฟล์จริงมี toolchain 4 ตัว (php-sdk, strawberry, nasm, winflexbison) กับ sources 10 ตัว (php, httpd, apr, apr-util, mod_fcgid, mariadb, pecl-redis, pecl-igbinary, pecl-imagick, imagemagick) ข้อสังเกตสามอย่างที่ต้องรู้ก่อนอ่านสคริปต์
- ค่า
"sha256": nullไม่ได้แปลว่าไม่ตรวจ มันแปลว่าต้นทางไม่ได้ประกาศ hash ไว้ ให้สคริปต์ไปใช้versions.lock.jsonแทน (อธิบายในหัวข้อถัดไป) stripคือจำนวนชั้นโฟลเดอร์ที่ตัดทิ้งตอนแตกไฟล์ tarball ส่วนใหญ่มีโฟลเดอร์ชั้นนอกชื่อhttpd-2.4.69\อยู่ข้างใน เราตัดมันทิ้ง (stripเป็น 1) เพื่อให้ได้src\httpd-2.4.69\CMakeLists.txtตรง ๆ ไม่ซ้อนสองชั้นimagemagickมีurlเป็นnullเพราะไม่ใช่ไฟล์ให้โหลด แต่เป็น git tag ที่ตอนที่ 5 ไป clone เอง สคริปต์เจอ url ว่างก็ข้ามเงียบ ๆ ไม่พิมพ์อะไร
อ่านฟังก์ชัน Get-One ตามลำดับที่มันรัน
- กรอง
-Onlyถ้าสั่ง-Only phpทุกชื่อที่ไม่ใช่phpจะถูกข้ามทันที (ก่อนถึงตรงนี้ บรรทัด$Only = @(...)ด้านบนแตกข้อความphp,httpdให้เป็นสองชื่อแล้ว) - ตั้งชื่อไฟล์จาก URL เอาท้าย path ของ URL มาเป็นชื่อไฟล์ใน
downloads\เช่นhttpd-2.4.69.tar.bz2 - ดาวน์โหลดเมื่อยังไม่มีไฟล์ หรือสั่ง
-Forceใช้curl.exeที่มากับ Windows (-fล้มเมื่อ HTTP error,-sSเงียบแต่โชว์ error,-Lตาม redirect,--retry 3ลองใหม่สามครั้ง) ดาวน์โหลดลงไฟล์ชื่อ.partก่อน แล้วค่อยMove-Itemเปลี่ยนชื่อเมื่อโหลดจบ ถ้าเน็ตหลุดกลางทางจะเหลือแต่.partไม่มีไฟล์ครึ่งเดียวที่ดูเหมือนสมบูรณ์ - คำนวณ sha256 ของไฟล์เสมอ แม้ไฟล์จะมีอยู่ก่อนแล้ว เพื่อให้ไฟล์ที่ค้างจากรอบก่อนถูกตรวจซ้ำทุกครั้ง
- เลือกค่าที่จะใช้เทียบ (
$want) ถ้าversions.jsonมี sha256 ก็ใช้ค่านั้น ถ้าเป็นnullก็ไปดูในversions.lock.jsonถ้าไม่มีทั้งสองที่ ก็ไม่มีอะไรให้เทียบ - ไม่ตรง = หยุดทันที
throwพร้อมพิมพ์ค่าที่ได้ (got) กับค่าที่ควรเป็น (want) สคริปต์ไม่แตกไฟล์ที่ hash ไม่ตรงเด็ดขาด - ตรวจ sha1 ซ้ำ เฉพาะรายการที่ระบุ
sha1ไว้ ซึ่งมีตัวเดียวคือmod_fcgidเพราะโครงการ Apache ประกาศ sha1 ไว้ให้ตัวนี้ - ถ้าไม่มีอะไรให้เทียบเลยจะพิมพ์
[TOFU]แล้วจด hash ที่ได้ลง$Lock - ข้ามการแตกไฟล์ถ้าโฟลเดอร์ปลายทางมีอยู่แล้ว (พิมพ์
already extracted) เว้นแต่สั่ง-Forceซึ่งจะลบโฟลเดอร์แล้วแตกใหม่ ข้อนี้มีกับดัก อธิบายในหัวข้อ "ถ้าพังตรงนี้" - แตกไฟล์ด้วย
tar.exeที่มากับ Windows 10 ขึ้นไป (bsdtar) อ่าน.zip.tar.bz2.tar.xz.tgzได้หมด ไม่ต้องติดตั้ง 7-Zip - บรรทัดสุดท้ายของสคริปต์ เขียน
$Lockกลับลงversions.lock.jsonเป็นรอบสุดท้าย
3. sha256 ที่ต้นทางประกาศ กับ TOFU ต่างกันยังไง
สองคำนี้เป็นหัวใจของความน่าเชื่อถือของทั้งซีรีส์ ผมเลยแยกอธิบายให้ชัด
แบบที่ 1: ต้นทางประกาศ hash ไว้เอง PHP, httpd, APR, APR-util, MariaDB ต้นทางเผยแพร่ sha256 ไว้ในหน้าที่ปล่อยเวอร์ชัน (php.net มี JSON, Apache มีไฟล์ .sha256 ข้าง tarball, MariaDB มี REST API) ผมคัดค่านั้นมาใส่ใน versions.json เองแล้ว ถ้าใครสลับไฟล์ระหว่างทางหรือที่ mirror hash ย่อมไม่ตรง และสคริปต์หยุด
แบบที่ 2: TOFU (Trust On First Use) ของบางตัวต้นทางไม่ได้ประกาศ hash ไว้ เช่น release ของ GitHub (php-sdk, winflexbison, Strawberry Perl) และแพ็กเกจ PECL ทั้งสามตัว วิธีที่ทำได้คือ ดาวน์โหลดครั้งแรกแล้วจด hash ไว้ ครั้งต่อไปค่อยเทียบกับที่จดไว้ มันป้องกันไม่ได้ว่าไฟล์ครั้งแรกถูกสลับหรือเปล่า แต่ป้องกันได้ว่าไฟล์ที่เคยดีอยู่เกิดเปลี่ยนไปทีหลัง
ในชุด kit ที่คุณโหลดมามีไฟล์ versions.lock.json ติดมาด้วย ผมจด hash ของแต่ละตัวไว้จากการดาวน์โหลดครั้งแรกบนเครื่องผม ผลคือเครื่องคุณจะไม่เห็นบรรทัด [TOFU] ในการรันครั้งแรก เพราะทุกตัวมีค่าในล็อกให้เทียบอยู่แล้ว และ hash ของ php-sdk, Strawberry Perl, NASM, winflexbison, mod_fcgid กับ PECL ทั้งสามจะถูกเทียบกับของที่ผมดาวน์โหลดไว้ ไม่ใช่เชื่อไฟล์แรกที่เจอ ถ้าอยากเห็นกลไก TOFU ทำงานจริง ให้ลบไฟล์ versions.lock.json แล้วรันใหม่ จะเห็น [TOFU] <ชื่อ> sha256=<64 ตัวอักษร> ขึ้นมาแทน
การเทียบกับล็อกบอกได้แค่ว่าไฟล์ตรงกับที่ผมเคยได้ ไม่ได้รับรองว่าต้นทางของไฟล์นั้นปลอดภัย ถ้าคุณจะเปลี่ยนเวอร์ชันของตัวที่เป็น TOFU (ตอนที่ 7 อธิบายขั้นตอน) ควรเปิดหน้า release ของต้นทางดูก่อนว่า tag และไฟล์ตรงกับที่ประกาศ แล้วค่อยให้สคริปต์จด hash ใหม่
4. รัน fetch ทีละขั้น
ขั้นที่ 4.1 สั่งรัน
ที่ไหน: pwsh (user ปกติ) โฟลเดอร์ C:\apm-build ใช้รูปแบบ pwsh -File แบบเดียวกับที่ build.cmd ใช้ ซึ่งข้ามเรื่อง ExecutionPolicy ของไฟล์ที่ดาวน์โหลดจากเน็ต (ไฟล์ใน zip มักติดเครื่องหมาย "มาจากอินเทอร์เน็ต" ทำให้นโยบาย RemoteSigned ปฏิเสธไม่ให้รัน)
pwsh -NoProfile -ExecutionPolicy Bypass -File scripts\00-fetch.ps1
ขั้นที่ 4.2 ดูผลระหว่างรัน
รอบแรกใช้เวลา 3-5 นาที ขึ้นกับความเร็วเน็ต ไฟล์ที่ใหญ่ที่สุดคือ Strawberry Perl (ประมาณ 290 MB) กับ MariaDB (ประมาณ 211 MB) จะเห็นบรรทัดเป็นคู่ [GET] แล้ว [OK] ต่อรายการ ผมย่อบางรายการออก
[GET] php-sdk 2.8.4
[OK] php-sdk -> C:\apm-build\toolchain\php-sdk
[GET] strawberry 5.42.3.1
[OK] strawberry -> C:\apm-build\toolchain\strawberry
...
[GET] php 8.4.27
[OK] php -> C:\apm-build\src\php-8.4.27
[GET] httpd 2.4.69
[OK] httpd -> C:\apm-build\src\httpd-2.4.69
...
[OK] pecl-imagick -> C:\apm-build\src\pecl-imagick-3.8.1
บรรทัดสุดท้ายที่ควรเห็นคือ pecl-imagick ไม่มีบรรทัดของ imagemagick เพราะถูกข้ามตามที่อธิบายไป ถ้ามี [ERR] ให้ข้ามไปหัวข้อ "ถ้าพังตรงนี้"
ขั้นที่ 4.3 ตรวจว่าไฟล์ครบ 13 ไฟล์
Get-ChildItem C:\apm-build\downloads | Select-Object Name, @{n='MB';e={[math]::Round($_.Length/1MB,1)}}
ควรได้ 13 แถว หน้าตาประมาณนี้ (ขนาดจากเครื่องผม)
Name MB
---- --
apr-1.7.6.tar.bz2 0.9
apr-util-1.6.5.tar.bz2 0.4
httpd-2.4.69.tar.bz2 8.1
igbinary-3.2.16.tgz 0.1
imagick-3.8.1.tgz 0.3
mariadb-11.8.9.tar.gz 211.4
mod_fcgid-2.3.9.tar.bz2 0.1
nasm-3.01-win64.zip 0.6
php-8.4.27.tar.xz 13.2
php-sdk-2.8.4.zip 34.4
redis-6.3.0.tgz 0.4
strawberry-perl-5.42.3.1-64bit-portable.zip 290.6
win_flex_bison-2.5.25.zip 1.0
ขั้นที่ 4.4 ตรวจว่า source ถูกแตกไฟล์
Get-ChildItem C:\apm-build\src -Name
Get-ChildItem C:\apm-build\toolchain -Name
apr-1.7.6
apr-util-1.6.5
httpd-2.4.69
mariadb-11.8.9
mod_fcgid-2.3.9
pecl-igbinary-3.2.16
pecl-imagick-3.8.1
pecl-redis-6.3.0
php-8.4.27
nasm
php-sdk
strawberry
winflexbison
ฝั่ง src ได้ 9 โฟลเดอร์ ฝั่ง toolchain ได้ 4 (ยังไม่มี vcpkg ตอนนี้ มันจะมาในหัวข้อ 7 และ imagemagick-windows จะมาในตอนที่ 5)
ขั้นที่ 4.5 ตรวจว่าแตกไฟล์ถูกชั้น
นี่คือการตรวจ strip ว่าได้ผล ถ้าแตกซ้อนสองชั้นไฟล์พวกนี้จะหาไม่เจอ และตอนที่ 3 จะล้มด้วย error ที่งง
Test-Path C:\apm-build\src\httpd-2.4.69\CMakeLists.txt
Test-Path C:\apm-build\src\apr-1.7.6\CMakeLists.txt
Test-Path C:\apm-build\src\apr-util-1.6.5\CMakeLists.txt
Test-Path C:\apm-build\src\mod_fcgid-2.3.9\modules\fcgid\CMakeLists.txt
ต้องได้ True ครบสี่บรรทัด
ขั้นที่ 4.6 ตรวจเครื่องมือที่โหลดมาว่ารันได้
ที่ตรวจสองตัวนี้เพราะเป็นตัวที่ vcpkg และ OpenSSL พึ่งใน build ภายหลัง และเป็นตัวที่ผิดตัวแล้วเจ็บที่สุด
C:\apm-build\toolchain\strawberry\perl\bin\perl.exe -e 'print "$^V $^O\n"'
C:\apm-build\toolchain\nasm\nasm.exe -v
v5.42.3 MSWin32
NASM version 3.01 compiled on Oct 10 2025
คำว่า MSWin32 สำคัญมาก เพราะ perl ที่มากับ Git for Windows เป็นแบบ cygwin (จะขึ้น cygwin แทน) สร้าง path แบบ Unix แล้วทำให้ build OpenSSL พัง เลยต้องใช้ Strawberry Perl ที่โหลดมานี้เท่านั้น
ขั้นที่ 4.7 รันซ้ำเพื่อดูว่าข้ามได้
pwsh -NoProfile -ExecutionPolicy Bypass -File scripts\00-fetch.ps1
ครั้งนี้เสร็จในไม่กี่วินาที (เวลาส่วนใหญ่หมดไปกับการคำนวณ hash ซ้ำ) เพราะไฟล์อยู่ครบ สคริปต์แค่คำนวณ hash ซ้ำแล้วพิมพ์ว่าแตกไฟล์แล้ว ผลที่ได้คือ (จาก log จริงของผม)
[OK] php-sdk (already extracted)
[OK] strawberry (already extracted)
[OK] nasm (already extracted)
[OK] winflexbison (already extracted)
[OK] php (already extracted)
...
[OK] pecl-imagick (already extracted)
ขั้นที่ 4.8 (ไม่บังคับ) ตรวจ hash ด้วยมือเทียบกับต้นทาง
ถ้าคุณอยากไม่เชื่อสคริปต์ผม ให้เทียบเอง ตัวอย่างกับ httpd
Get-FileHash C:\apm-build\downloads\httpd-2.4.69.tar.bz2 -Algorithm SHA256 | Select-Object -ExpandProperty Hash
แล้วเปิดไฟล์ https://downloads.apache.org/httpd/httpd-2.4.69.tar.bz2.sha256 ในเบราว์เซอร์เทียบ ค่าต้องตรงกัน (PowerShell พิมพ์ตัวพิมพ์ใหญ่ ส่วนไฟล์ของ Apache เป็นตัวพิมพ์เล็ก ไม่ต้องสนใจต่างกันตรงนี้) ของผมขึ้นต้นด้วย C5E6EBC66E34
ใช้ -Only กับ -Force เมื่อต้องการโหลดเฉพาะบางตัว
ตอนที่ 7 จะใช้ตัวเลือกพวกนี้ตอนอัปเดตเวอร์ชัน สั่งหลายชื่อพร้อมกันได้ตรง ๆ ด้วย -File คั่นด้วยจุลภาค
pwsh -NoProfile -ExecutionPolicy Bypass -File scripts�-fetch.ps1 -Only php,httpd
มันทำงานได้เพราะบรรทัดที่เพิ่มเข้ามาใต้ $ErrorActionPreference (บรรทัดที่ขึ้นต้น $Only = @(...)) เรื่องคือ pwsh -File ไม่แปลง php,httpd เป็นอาร์เรย์ ให้ส่งเข้าไปเป็นข้อความก้อนเดียว "php,httpd" ใน $Only เลยมีสมาชิกตัวเดียว และชื่อ httpd ไม่ตรงกับอะไร สคริปต์ก็ข้ามทุกรายการเงียบ ๆ โดยไม่มี error สคริปต์รุ่นใหม่เลยแตกข้อความเองก่อนใช้ ไล่ทุกค่าใน $Only ผ่าน -split ',' ตัดช่องว่างหัวท้ายด้วย .Trim() ทิ้งค่าว่างด้วย Where-Object { $_ } แล้วครอบด้วย @(...) ให้เป็นอาร์เรย์เสมอ ผลคือ -Only php, -Only php,httpd และ -Only "php, httpd" ได้ผลเหมือนกัน
ถ้าอยากเช็กว่าแตกถูก ให้รันแล้วดูว่ามีบรรทัด [OK] หรือ [GET] ของทั้งสองชื่อ (ถ้าไฟล์กับโฟลเดอร์มีอยู่แล้วจะขึ้น [OK] php (already extracted) กับ [OK] httpd (already extracted)) ใครที่ใช้ kit รุ่นเก่าเคยต้องสั่งผ่าน -Command "& .\scripts�-fetch.ps1 -Only php,httpd" แทน เพราะรุ่นนั้นยังไม่แตกข้อความเอง รุ่นปัจจุบันไม่ต้องแล้ว
ส่วน -Force ใส่ท้ายคำสั่งได้เลย จะโหลดไฟล์ใหม่ทับและลบโฟลเดอร์ปลายทางแตกใหม่
5. vcpkg กับ lib ที่ Apache ต้องใช้
Apache httpd ตัวมันเองมีแต่โค้ด C ของมัน ส่วนที่ทำให้มันคุย HTTPS, HTTP/2, บีบอัดแบบ brotli ได้ มาจาก lib ภายนอก ถ้าคุณเคยลง Apache บน Linux ด้วย apt install คำสั่งเดียวได้ lib พวกนี้ครบ แต่บน Windows ไม่มีใครดูแลให้ เราเลยใช้ vcpkg ซึ่งเป็นตัวจัดการ package ของ C/C++ จาก Microsoft มันดาวน์โหลด source ของแต่ละ lib แล้วคอมไพล์ด้วย MSVC ในเครื่องเราให้ ABI ตรงกับ Apache ที่เราจะ build
manifest: บอกว่าต้องการอะไร
vcpkg มีสองโหมด โหมดที่ผมใช้เรียกว่า manifest คือเขียนรายการ lib ที่ต้องการไว้ในไฟล์ vcpkg.json ของโปรเจกต์ แล้วสั่ง vcpkg install ไฟล์นี้อยู่ที่ deps\apache\vcpkg.json (ผมย่อ hash ของ baseline)
{
"name": "apm-apache-deps",
"version-string": "1",
"builtin-baseline": "bd8298ae21…",
"dependencies": [
"openssl", "pcre2", "zlib", "nghttp2", "brotli",
"expat", "libxml2", "jansson", "curl"
]
}
builtin-baseline คือ commit ของคลัง vcpkg ที่ล็อกเวอร์ชันของ lib ทุกตัวให้ตายตัว ถ้าไม่ล็อก ทุกครั้งที่ vcpkg อัปเดตเราจะได้ lib คนละรุ่นโดยไม่รู้ตัว ผลคือ build รอบเดียวกันสองเครื่องออกมาไม่เหมือนกัน ในไฟล์จริง baseline เป็น commit id 40 ตัวอักษร ขึ้นต้นด้วย bd8298ae21
ทั้ง 9 ตัวใช้ทำอะไร สรุปตามที่ configure ของ httpd ตรวจเจอใน log ของผม (ส่วน Summary of feature detection) กับที่ dumpbin ในตอนที่ 3 ยืนยัน
| lib | ใช้กับ | หมายเหตุ |
|---|---|---|
| openssl | mod_ssl, mod_md, apr_crypto_openssl |
HTTPS/TLS ทั้งหมด (เป็นเรื่องของหัวข้อ 6) |
| pcre2 | libhttpd.dll |
regex ของ mod_rewrite, <LocationMatch> ฯลฯ |
| zlib | mod_deflate, libcurl, libxml2 |
บีบอัด gzip/deflate |
| nghttp2 | mod_http2 |
HTTP/2 |
| brotli | mod_brotli |
บีบอัด brotli |
| expat | libaprutil |
อ่าน XML ให้ APR-util |
| libxml2 | mod_xml2enc |
จัดการ encoding ในเอกสาร XML/HTML ที่ proxy ผ่าน |
| jansson | mod_md |
อ่าน/เขียน JSON ของ ACME |
| curl | mod_md |
ให้ mod_md คุยกับ Let's Encrypt |
vcpkg ยังลากของที่ lib เหล่านี้ต้องใช้ตอน build มาให้เองด้วย เช่น libiconv (ตัวที่ libxml2 ต้องการ) กับ vcpkg-cmake รวมแล้วบรรทัด * ... ใน log เป็นของที่ถูกติดตั้งในฐานะ dependency เครื่องมือที่ vcpkg ใช้ (CMake, Ninja, Perl, NASM, msys2) มันดาวน์โหลดมาเก็บเองใน toolchain\vcpkg\downloads\tools\ ไม่ไปยุ่งกับของที่คุณติดตั้งในเครื่อง
6. OpenSSL 3.5 LTS ด้วย overlay port
นี่คือส่วนที่ผมตัดสินใจเองและต้องอธิบายเหตุผลให้ได้ vcpkg รุ่นที่ baseline ชี้อยู่ให้ OpenSSL 3.6.5 ซึ่งเป็นรุ่น non-LTS และหมดระยะซัพพอร์ตภายในเดือนพฤศจิกายน 2026 ซึ่งก็คือเดือนหน้า ส่วน OpenSSL 3.5 เป็นรุ่น LTS ซัพพอร์ตถึงเมษายน 2030 สำหรับ web server ที่ตั้งใจให้ตามแพตช์ความปลอดภัยทุกรอบ ผมเลือก LTS ไม่ต้องย้ายรุ่นใหญ่อีกในเร็ว ๆ นี้
vcpkg มีกลไก overlay port รองรับพอดี คือบอกให้ใช้ port (สูตร build ของ lib หนึ่งตัว) จากโฟลเดอร์ของเราแทนตัวที่อยู่ในคลัง vcpkg โฟลเดอร์ของเราคือ ports-overlay\openssl\ ใน kit ข้างในเป็นสูตร OpenSSL ฉบับเต็ม (portfile, patch และ vcpkg.json) ที่ตั้งเป็นรุ่น 3.5.9 สองจุดที่ต้องแตะทุกครั้งที่เปลี่ยนรุ่นคือเลขเวอร์ชันใน vcpkg.json กับ SHA512 ของ tarball ใน portfile.cmake
{
"name": "openssl",
"version": "3.5.9",
...
}
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO openssl/openssl
REF "openssl-${VERSION}"
SHA512 ab29a6ed40dd8c74…
PATCHES
cmake-config.patch
command-line-length.patch
script-prefix.patch
windows/install-layout.patch
windows/install-pdbs.patch
windows/install-programs.diff
unix/android-cc.patch
unix/move-openssldir.patch
unix/no-empty-dirs.patch
unix/no-static-libs-for-shared.patch
)
บรรทัด REF "openssl-${VERSION}" ดึงเลขจาก vcpkg.json เลยแก้เวอร์ชันที่เดียวก็ตามไปทั้งสองไฟล์ ส่วน SHA512 คือ hash ของไฟล์ https://github.com/openssl/openssl/archive/openssl-3.5.9.tar.gz ถ้าไฟล์ที่ vcpkg โหลดมา hash ไม่ตรง มันหยุดเหมือนที่ 00-fetch.ps1 ทำ ส่วน 10 patch ในรายการ เป็นของ vcpkg เองทั้งหมด ผมลองแล้วใช้กับ 3.5.9 ได้โดยไม่ต้องแก้ แต่รุ่นอื่นต้องลองเองเสมอ
ตอนที่ 6 ที่ build PHP จะได้ DLL ของ OpenSSL อีกชุดจากกลุ่ม deps ของ PHP team (ผมวัดได้รุ่น 3.0.22 ในตอนนั้น) สองชุดนี้แยกกัน ฝั่ง Apache ใช้ 3.5.9 ที่เรา build เอง ฝั่ง PHP ใช้ของ PHP team เพื่อให้ ABI ตรงกับ PHP official รายละเอียดอยู่ในตอนที่ 6
7. 10-deps-vcpkg.ps1 ทีละบรรทัด และรันจริง
นี่คือสคริปต์เต็ม
# 10-deps-vcpkg.ps1 - build Apache's third-party libs from source with vcpkg (manifest mode)
# OpenSSL comes from ports-overlay\openssl (3.5 LTS) instead of the vcpkg default.
$ErrorActionPreference = 'Stop'
$Root = Split-Path $PSScriptRoot -Parent
$Vcpkg = "$Root\toolchain\vcpkg\vcpkg.exe"
$Out = "$Root\build\vcpkg_installed"
New-Item -ItemType Directory -Force "$Root\build\logs" | Out-Null
# private vcpkg checkout (never the shared C:\vcpkg), at least as new as the manifest baseline
if (-not (Test-Path $Vcpkg)) {
$baseline = (Get-Content "$Root\deps\apache\vcpkg.json" -Raw | ConvertFrom-Json).'builtin-baseline'
git clone --quiet https://github.com/microsoft/vcpkg.git "$Root\toolchain\vcpkg"
git -C "$Root\toolchain\vcpkg" checkout --quiet $baseline
& "$Root\toolchain\vcpkg\bootstrap-vcpkg.bat" -disableMetrics
if (-not (Test-Path $Vcpkg)) { throw '[ERR] vcpkg bootstrap failed' }
}
$env:Path = ($env:Path -split ';' | Where-Object { $_ -notmatch '(?i)xampp' }) -join ';'
$env:VCPKG_DISABLE_METRICS = '1'
& $Vcpkg install --triplet x64-windows `
--x-manifest-root="$Root\deps\apache" `
--x-install-root="$Out" `
--overlay-ports="$Root\ports-overlay" `
--clean-after-build 2>&1 | Tee-Object "$Root\build\logs\vcpkg-apache.log" | Select-Object -Last 25
if ($LASTEXITCODE) { throw "[ERR] vcpkg install failed (log: build\logs\vcpkg-apache.log)" }
Write-Host "[OK] deps -> $Out\x64-windows"
อ่านตามลำดับที่รัน
- บรรทัด 4-7 กำหนด path ของ
vcpkg.exeผลลัพธ์ (build\vcpkg_installed) และสร้างโฟลเดอร์build\logs - บล็อก
if (-not (Test-Path $Vcpkg))ทำเฉพาะครั้งแรกที่ยังไม่มี vcpkg อ่าน commit id จากbuiltin-baselineใน manifest,git cloneคลัง vcpkg ลงtoolchain\vcpkg,git checkoutไปที่ commit นั้น แล้วรันbootstrap-vcpkg.batซึ่งโหลดvcpkg.exeให้ ตั้งใจให้เป็น checkout ส่วนตัวในโฟลเดอร์ของโปรเจกต์ ไม่ใช้C:\vcpkgที่คุณอาจมีใช้ร่วมกับงานอื่น เพื่อไม่ให้สองงานเหยียบกัน - บรรทัด
$env:Path = ...ถอด path ที่มีคำว่า xampp ออกจาก PATH เฉพาะใน process นี้ กันperl,phpฯลฯ ของ XAMPP หลุดเข้ามาแทนตัวที่ควรใช้ ถ้าไม่มี XAMPP บรรทัดนี้ไม่ทำอะไร VCPKG_DISABLE_METRICSปิดการส่งสถิติการใช้งานของ vcpkg ไปยัง Microsoft- คำสั่ง
vcpkg installมี 5 ตัวเลือก--triplet x64-windowsสถาปัตยกรรม x64 แบบ DLL (ไม่ใช่ static) ได้ไฟล์.dllข้างๆ.libซึ่งเป็นแบบที่ Apache ต้องการ--x-manifest-rootชี้ไปโฟลเดอร์ที่มีvcpkg.json--x-install-rootติดตั้งผลลัพธ์ลงbuild\vcpkg_installedในโปรเจกต์ ไม่ใช่ที่กลางของ vcpkg--overlay-portsชี้ไปports-overlayเพื่อให้ OpenSSL 3.5.9 ชนะ (หัวข้อ 6)--clean-after-buildลบโฟลเดอร์ต้นไม้ build ชั่วคราวของแต่ละ lib ทันทีที่เสร็จ ประหยัดดิสก์หลาย GB
- ท่อ
2>&1 | Tee-Object ... | Select-Object -Last 25รวม error เข้า output, เขียน log เต็มลงbuild\logs\vcpkg-apache.logและโชว์บนจอเฉพาะ 25 บรรทัดสุดท้าย ที่มันสั้นเพราะ vcpkg พ่นข้อความยาวมาก $LASTEXITCODEถ้า vcpkg คืนค่าไม่ใช่ 0 สคริปต์throwพร้อมบอกที่อยู่ของ log
ขั้นที่ 7.1 สั่งรัน
ที่ไหน: pwsh (user ปกติ) โฟลเดอร์ C:\apm-build เตรียมใจว่ารอบแรกนาน ประมาณ 45 นาทีบนเครื่องผม (i5-12500H) โดย OpenSSL กับ libiconv ช้าที่สุด จอจะนิ่งไปนานช่วงนั้น ไม่ได้ค้าง ถ้าอยากรู้ว่ายังทำงานอยู่ ให้เปิด Task Manager ดูว่ามีโปรเซส cl.exe หรือ nmake กินซีพียูอยู่
pwsh -NoProfile -ExecutionPolicy Bypass -File scripts\10-deps-vcpkg.ps1
ขั้นที่ 7.2 ดูผลตอนจบ
จอจะแสดงแค่ 25 บรรทัดสุดท้าย ท้ายสุดจะลงท้ายด้วยบรรทัดสรุปของ vcpkg กับ [OK] ของสคริปต์ ด้านล่างเป็นของจริงจาก log ของผมตอนรันซ้ำหลัง cache พร้อมแล้ว (เลยขึ้นว่า already installed) รอบแรกของคุณจะเป็นบรรทัดของ "will be built and installed" แทน แต่ 3 บรรทัดท้ายหน้าตาเหมือนกัน ต่างแค่เวลา
pcre2 provides pkg-config modules:
# Posix compatible interface to libpcre2-8
libpcre2-posix
All requested installations completed successfully in: 323 us
[OK] deps -> C:\apm-build\build\vcpkg_installed\x64-windows
323 us ในรอบของผมแปลว่า vcpkg ไม่ได้ทำอะไรเลย รอบแรกของคุณตรงนี้จะเป็นเวลาหลักนาที ถ้าอยากเห็นรายการ package ที่ติดตั้ง ให้ค้นใน log เต็ม
Select-String -Path C:\apm-build\build\logs\vcpkg-apache.log -Pattern 'x64-windows@' | ForEach-Object Line
ผลในเครื่องผม (รอบที่ใช้ cache) แสดงเลขรุ่นของ lib ทุกตัว
brotli:[email protected]
curl[core,sspi,ssl]:[email protected]
expat:[email protected]
jansson:[email protected]
* libiconv:[email protected]#1
libxml2[core,zlib,iconv]:[email protected]
nghttp2:[email protected]
openssl:[email protected]
pcre2[core,platform-default-features,jit]:[email protected]
* vcpkg-cmake:x64-windows@2025-08-07
* vcpkg-cmake-config:x64-windows@2026-07-21
* vcpkg-cmake-get-vars:x64-windows@2025-05-29
* vcpkg-make:x64-windows@2026-07-09#2
zlib:[email protected]#2
ให้ดูบรรทัด openssl:[email protected] เป็นตัวชี้ว่า overlay ทำงาน ถ้าเห็น 3.6.5 แปลว่า overlay ไม่ถูกใช้ ให้กลับไปเช็กว่าโฟลเดอร์ ports-overlay\openssl มีอยู่จริง
ขั้นที่ 7.3 ตรวจไฟล์ .lib ที่ Apache จะลิงก์
Get-ChildItem C:\apm-build\build\vcpkg_installed\x64-windows\lib -File -Name
brotlicommon.lib
brotlidec.lib
brotlienc.lib
charset.lib
iconv.lib
jansson.lib
libcrypto.lib
libcurl.lib
libexpat.lib
libssl.lib
libxml2.lib
nghttp2.lib
pcre2-16.lib
pcre2-32.lib
pcre2-8.lib
pcre2-posix.lib
z.lib
ต้องมี 17 ไฟล์ ถ้าขาด libssl.lib หรือ libcrypto.lib แปลว่า OpenSSL ไม่ผ่าน ให้ดูหัวข้อ "ถ้าพังตรงนี้"
ขั้นที่ 7.4 ตรวจเลขรุ่นของ DLL ที่ build ออกมาจริง
ขั้นนี้ยืนยันว่าไฟล์ที่จะถูกคัดลอกไปข้าง httpd.exe ในตอนที่ 3 เป็นรุ่นที่เราตั้งใจ ไม่ใช่ที่ไหนก็ไม่รู้
$b = 'C:\apm-build\build\vcpkg_installed\x64-windows\bin'
foreach ($n in 'libcrypto-3-x64','libssl-3-x64','libcurl','libxml2','z') { "{0,-18} {1}" -f $n, (Get-Item "$b\$n.dll").VersionInfo.ProductVersion }
libcrypto-3-x64 3.5.9
libssl-3-x64 3.5.9
libcurl 8.23.0
libxml2 2.15.4
z 1.3.2
ชื่อไฟล์ libcrypto-3-x64.dll ยังมีเลข 3 อยู่ แม้ตัวเนื้อเป็น 3.5.9 เพราะเลขในชื่อคือรุ่นใหญ่ (major) ของ ABI ของ OpenSSL ไม่ใช่เลขรุ่นเต็ม
ขั้นที่ 7.5 ตรวจว่า vcpkg ชี้ commit ถูกตัว
git -C C:\apm-build\toolchain\vcpkg log -1 --format=%h
bd8298ae21
ต้องขึ้นต้นด้วยตัวเดียวกับ builtin-baseline ในไฟล์ manifest
ขั้นที่ 7.6 ย้ำว่าสคริปต์รันซ้ำได้
รันขั้น 7.1 อีกรอบ จะเสร็จภายในไม่กี่วินาที เพราะ vcpkg เก็บ binary cache ของแต่ละ package ไว้ในเครื่อง (โดยปริยายอยู่ที่ %LOCALAPPDATA%\vcpkg\archives) ผลคือเปลี่ยนเวอร์ชัน lib ตัวเดียว ตัวอื่นไม่ถูกคอมไพล์ใหม่ ทั้ง build.cmd รันซ้ำรวมกันที่ผมวัดได้ ขั้น vcpkg ใช้ 0.1 นาที
มีโฟลเดอร์ C:\apm-build\build\vcpkg_installed\x64-windows ที่ข้างในมี include\, lib\ (17 ไฟล์ .lib) และ bin\ (DLL 18 ตัว) นี่คือของที่ตอนที่ 3 จะดึงไปใช้ทั้งหมด
8. ถ้าพังตรงนี้
ตารางนี้รวมอาการที่เจอจริงหรือที่โค้ดของสคริปต์ออกแบบให้ดักไว้ ของที่ผมไม่เคยเจอเองผมระบุไว้ว่าอ่านจากโค้ด
| อาการ | สาเหตุ | วิธีแก้ |
|---|---|---|
[ERR] sha256 mismatch <ชื่อ> พร้อม got กับ want |
ไฟล์ที่โหลดมาไม่ตรง hash ที่ล็อกไว้ อาจโหลดไม่สมบูรณ์ mirror ส่งไฟล์ผิด หรือไฟล์ต้นทางถูกเปลี่ยน | ลบไฟล์นั้นใน downloads\ แล้วรันใหม่ถ้ายังเหมือนเดิม ห้ามแก้ hash ให้ผ่านเฉย ๆ ให้ไปเทียบกับหน้าต้นทางก่อน (ขั้น 4.8) |
download failed: <url> |
เน็ตหลุด, proxy ขององค์กรบล็อก, URL ของต้นทางเปลี่ยน | ลองเปิด URL นั้นในเบราว์เซอร์ ถ้าเปิดได้แต่ curl.exe ไม่ได้ ให้เช็ก proxy ไฟล์ .part ที่ค้างลบทิ้งได้ |
รันแล้วเงียบ ไม่มี [OK] สักบรรทัด |
ชื่อใน -Only สะกดไม่ตรงกับชื่อใน versions.json (เช่น apache แทน httpd) ทุกรายการเลยถูกข้าม หรือใช้ kit รุ่นเก่าที่ยังไม่แตกข้อความ a,b เอง |
เทียบชื่อกับ key ใน versions.json ถ้าเป็น kit เก่าให้โหลด kit ใหม่ หรือสั่งผ่าน -Command "& .\scripts�-fetch.ps1 -Only a,b" |
ขึ้น [OK] <ชื่อ> (already extracted) แต่ไฟล์ข้างในไม่ครบ |
แตกไฟล์ค้างกลางทาง (ดิสก์เต็ม) โฟลเดอร์ปลายทางถูกสร้างไปแล้ว รอบหน้าสคริปต์เห็นโฟลเดอร์ก็ข้าม (อ่านจากโค้ด) | ลบโฟลเดอร์นั้นใน src\ หรือ toolchain\ ทิ้ง แล้วรันใหม่ หรือใส่ -Force |
extract failed: <ไฟล์> |
tar.exe อ่านไฟล์ไม่ได้ ไฟล์เสีย หรือ path ยาวเกิน |
ลบไฟล์ใน downloads\ โหลดใหม่ ถ้ายังเป็น ให้เช็กว่าโฟลเดอร์โปรเจกต์ไม่ลึกเกินไป ใช้ C:\apm-build ตามที่บอก |
A parameter cannot be found that matches parameter name 'AsHashtable' |
รันด้วย Windows PowerShell 5.1 ไม่ใช่ pwsh 7 | เปิด pwsh (ขั้น 1.1) |
ไม่มีไฟล์ .lib ของ OpenSSL / [ERR] vcpkg install failed |
build ของ lib ใด lib หนึ่งล้ม | เปิด build\logs\vcpkg-apache.log เลื่อนหาข้อความ error ตัวแรก vcpkg มักบอกชื่อ log ย่อยของ package นั้นไว้ในบรรทัดท้าย ๆ |
| OpenSSL ล้มด้วย path แปลก ๆ แบบ Unix | perl ของ Git (cygwin) แทรกเข้ามาใน PATH | ทำตามขั้น 4.6 ให้ได้ MSWin32 และเอาโฟลเดอร์ perl ของ Git ออกจาก PATH ของ session นั้นถ้าตั้งไว้ |
warning: ... ignoring mismatched VCPKG_ROOT environment value C:\vcpkg |
มีตัวแปร VCPKG_ROOT ของ vcpkg ตัวอื่นในเครื่อง |
ไม่ใช่ปัญหา เป็นแค่คำเตือน vcpkg ใช้ตัวในโปรเจกต์ตามที่ตั้งใจ (เจอใน log จริงของผม) |
| ช้ามากเป็นสองเท่า | Defender สแกนไฟล์ .obj นับหมื่นไฟล์ |
ตั้ง exclusion ตามตอนที่ 1 (ต้องใช้ admin) |
| สั่งซ้ำแล้ว vcpkg ยังคอมไพล์ OpenSSL ใหม่ทั้งที่ไม่ได้แก้อะไร | ลบ binary cache ใน %LOCALAPPDATA%\vcpkg\archives หรือเปลี่ยน compiler (อัปเดต MSVC ทำให้ hash ของ compiler เปลี่ยน) อ่านจากพฤติกรรมของ vcpkg ที่คิด hash ตาม compiler |
ปล่อยให้มันรันจบ รอบหน้าจะกลับมาเร็ว |
ถ้าเจออาการนอกตาราง ให้เปิด log ก่อนเสมอ ข้อความบน console ถูกตัดเหลือ 25 บรรทัดสุดท้าย แต่ log เต็มอยู่ที่ C:\apm-build\build\logs\vcpkg-apache.log และข้อความ error ตัวแรกที่บอกต้นเหตุจริงมักอยู่เหนือ 25 บรรทัดนั้นขึ้นไป
9. เช็กลิสต์ก่อนไปตอนที่ 3
ทุกข้อต้องจริงก่อนไปต่อ ถ้าข้อไหนไม่ได้ ให้กลับไปขั้นที่อ้างถึง
C:\apm-build\downloadsมี 13 ไฟล์ และ00-fetch.ps1รันซ้ำแล้วขึ้นalready extractedครบทุกบรรทัด (ขั้น 4.3 และ 4.7)C:\apm-build\srcมี 9 โฟลเดอร์ และTest-PathของCMakeLists.txtสี่ตัวได้True(ขั้น 4.4 และ 4.5)perl.exeของ Strawberry ตอบMSWin32(ขั้น 4.6)C:\apm-build\build\vcpkg_installed\x64-windows\libมี 17 ไฟล์.libรวมlibssl.libกับlibcrypto.lib(ขั้น 7.3)libcrypto-3-x64.dllมี ProductVersion เป็น3.5.9(ขั้น 7.4)C:\apm-build\build\logs\vcpkg-apache.logลงท้ายด้วยAll requested installations completed successfully(ขั้น 7.2)
ใครอยากได้ 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 ฐานข้อมูล และเว็บของเรา
สารบัญ · ตอนก่อนหน้า: ตอนที่ 1 เตรียมเครื่องมือ · ตอนถัดไป: ตอนที่ 3 build Apache httpd
ตอนที่ 3 จะเอา source ใน src\ กับ lib ใน build\vcpkg_installed มาประกอบเป็น Apache httpd กับ mod_fcgid และจะได้เห็นว่าสคริปต์ไล่หา DLL ที่ต้องวางข้าง httpd.exe ยังไง ถ้าคุณทำตามมาถึงตรงนี้ ส่วนที่นานที่สุดของ Apache ผ่านไปแล้ว เดี๋ยวกลับมาแก้เพิ่มให้ภายหลังครับ
อยากให้เราทำให้ไหม?
ให้เราช่วยติดตั้ง ตั้งค่า ย้ายระบบ หรือแก้ปัญหาเซิร์ฟเวอร์ เพื่อให้คุณมีเวลาไปทำงานที่สำคัญกว่า
เคยเจองานแบบนี้ไหม? ติดตรงไหน?
มาแลกวิธีกันต่อในบอร์ด LinuxThai



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