logo
Apache Lounge
Webmasters

 

About Forum Index Downloads Search Register Log in  RSS Apache Lounge  


Keep Server Online

If you find the Apache Lounge, the downloads and overall help useful, please express your satisfaction with a donation.

or

Bitcoin

A donation makes a contribution towards the costs, the time and effort that's going in this site and building.

Thank You! Steffen

Your donations will help to keep this site alive and well, and continuing building binaries. Apache Lounge is not sponsored.



Post new topic   Forum Index -> How-to's & Documentation & Tips View previous topic :: View next topic
Reply to topic   Topic: HOWTO: Building Apache and dependencies using CMake
Author
tangent



Joined: 16 Aug 2020
Posts: 39
Location: UK

PostPosted: Fri 18 Dec '20 19:10    Post subject: HOWTO: Building Apache and dependencies using CMake Reply with quote

This is an update to the previous excellent work from idblew and others mentioned in post
https://www.apachelounge.com/viewtopic.php?t=6462


Change log :

18 Dec 2020 : 1.0 - Initial release.
19 Dec 2020 : 1.1 - Switch to Strawberry Perl. Remove LIBSSH2, YAJL and MOD_SECURITY.
05 Jan 2021 : 1.2 - Add LUA to src tree.


In this variant I have chosen a command line solution, developing a batch file (post below) to build the required packages from source.

If appropriate, the following can be hosted in a virtual machine derived from an image at https://developer.microsoft.com/en-us/windows/downloads/virtual-machines, into which you configure the necessary toolset, viz:
    Visual Studio Community 2019 - currently v16.8.3
    Visual Studio Build Tools 2019 - currently v16.8.3
    CMake for Windows - currently v3.18 (bundled with Visual Studio)
    Strawberry Perl 64-bit - currently v5.32
    Netwide Assembler (NASM) - currently v2.15

Several members have requested details on building ZLIB, LUA, APR-ICONV, etc., and these are covered in the process below using CMake where possible, and NMake.

Sequence
  1. Preparation
    Prepare the following structure with source folders based on the appropriate version of each package you choose to build. This list matches the latest package versions at the time of writing.

    You can of course change the folder path names in the source tree (no whitespace advised), updating the paths in the build batch file accordingly.

    Code:
    C:\Development
       └ Apache24
          ├ src
          │   ├ apr-1.7.0
          │   ├ apr-iconv-1.2.2
          │   ├ apr-util-1.6.1
          │   ├ brotli-1.0.9
          │   ├ curl-7.74.0
          │   ├ expat-2.2.10
          │   ├ httpd-2.4.46
          │   ├ jansson-2.13.1
          │   ├ libxml2-2.9.10
          │   ├ lua-5.3.6
          │   ├ mod_fcgid-2.3.9
          │   ├ nghttp2-1.42.0
          │   ├ openssl-1.1.1i
          │   ├ pcre-8.44
          │   └ zlib-1.2.11
          │
          └ build

    Note you don't need to prepare sub-folders below 'build', which get created during build process.

  2. Source Packages
    Download and extract the required packages into the appropriate source folders shown above.

    Note, the build batch file does patch source files where necessary (using Perl), but you may well wish to apply later security patches and updates manually to the source structures as appropriate.

  3. Build Batch File
    Download the build batch file code from the post below in this thread, and save it in the above 'build' folder as build_all.bat

    a) Edit the build batch file to set BUILD_BASE as required, if using a different path to that above.
    b) Update the target PREFIX, if the default location of C:\Apache24 isn't acceptable (again no whitespace advised).
    c) Choose 32 or 64 bit builds by setting the PLATFORM variable in the build batch file to x86 or x64 as required.
    d) Similarly, set the variable BUILD_TYPE to Release or Debug.
    e) Update the path to the vcvarsall.bat file if need be to match your Visual Studio toolset.
    f) Edit the package version details to match your downloads as appropriate.

  4. Additional Notes
    a) The build process doesn't clear source folders in case they've been patched. However, the package folder below 'build' is deleted each time.
    b) Package EXPAT is now required when building APR-UTIL
    c) Building APR-ICONV will rebuild APR using NMake, the output of which goes into the APR source folder rather than the build folder.
    d) CMakeLists.txt for LUA 5.3 is an extra file which can be downloaded from https://apaste.info/yOSR
    e) If you require LUA 5.4 you will need to patch the mod_lua module source in httpd 2.4.46
    f) You may choose to build further packages to provide additional functionality in CURL and NGHTTP2, e.g. packages LIBSSH2, LIBEV, LIBEVENT, C-ARES, CUNIT, JEMALLOC, PYTHON, etc. These are beyond the scope of this HOWTO but can be added using similar build logic.
    g) It may be necessary to turn off real time AV scanning to prevent file lock failures during the build process.
    h) The various Perl inline patch edit sections may look daunting but note there are numerous ^ escape characters in there to cope with the vagaries of batch file continuation lines, embedded double quotes, and right parentheses in "if then else" blocks.

  5. Build
    Open a command or Powershell window, change to the above build folder, and run the build_all.bat batch file. Ideally, redirect the build process output to a log file so you can check for errors. If using Powershell, you can use the tee command, viz:

    Code:
    C:\Development\Apache24\build> .\build_all.bat 2>&1 | tee build_all.log

  6. Checks
    When finished search the log file output for fatal errors (hopefully none).

    Confirm Apache files have been created below PREFIX and run as expected, viz:

    Code:
    cd /d C:\Apache24\bin
    .\openssl version
    .\httpd -V
    .\httpd

    I hope people find this updated HOWTO useful.


Last edited by tangent on Tue 05 Jan '21 17:04; edited 3 times in total
Back to top
tangent



Joined: 16 Aug 2020
Posts: 39
Location: UK

PostPosted: Fri 18 Dec '20 19:11    Post subject: Reply with quote

Change log:

18 Dec 2020 : 1.0 - Initial release.
19 Dec 2020 : 1.1 - Switch CURL to SCHANNEL for mod_md. Remove LIBSSH2, YAJL and MOD_SECURITY. Add LUA_COMPAT_ALL compile option to LUA.
03 Jan 2021 : 1.2 - Move CURL build after NGHTTP2 and update options to include HTTP2, BROTLI and UNICODE.


Code:
@echo off

rem @(#)build_all.bat 1.2 - 2021-01-03 tangent
rem
rem 1.0 - Initial release. 2020-12-17
rem 1.1 - Switch CURL to SCHANNEL (WINSSL) rather than OpenSSL, for mod_md.
rem       Accordingly, remove LIBSSH2. Remove YAJL and MOD_SECURITY since not core
rem       ASF/Apache modules. Add LUA_COMPAT_ALL compile option to LUA. 2020-12-18
rem 1.2 - Move CURL build after NGHTTP2 and update options to include HTTP2, BROTLI and UNICODE. 2021-01-03

rem Apache build command file for Windows.
rem
setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

rem Set required build base folder and target prefix.
rem
set BUILD_BASE=C:\Development\Apache24\build
set PREFIX=C:\Apache24

rem Set required build platform to x86 or x64.
rem
rem set PLATFORM=x86
set PLATFORM=x64

rem Set required build type to Release or Debug.
rem
rem set BUILD_TYPE=Debug
set BUILD_TYPE=Release

rem Request PDB files (ON) or not (OFF).
rem
set INSTALL_PDB=OFF

rem Define build packages with their version. This is also the recommended build order.

set ZLIB=zlib-1.2.11
set PCRE=pcre-8.44
set EXPAT=expat-2.2.10
set OPENSSL=openssl-1.1.1i
set LIBXML2=libxml2-2.9.10
set JANSSON=jansson-2.13.1
set BROTLI=brotli-1.0.9
set LUA=lua-5.3.6
set APR=apr-1.7.0
set APR-ICONV=apr-iconv-1.2.2
set APR-UTIL=apr-util-1.6.1
set NGHTTP2=nghttp2-1.42.0
set CURL=curl-7.74.0
set HTTPD=httpd-2.4.46
set MOD_FCGID=mod_fcgid-2.3.9

rem ------------------------------------------------------------------------------
rem
rem Define path to MS Visual Studio build environment script.

set VCVARSALL=C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat

if exist "%VCVARSALL%" (
  call "%VCVARSALL%" %PLATFORM%
) else (
  echo Could not find "%VCVARSALL%"
  exit /b
)

rem ------------------------------------------------------------------------------
rem
rem ZLIB

rem Check for package and switch to source folder.
rem
call :check_package_source %ZLIB%

if !STATUS! == 0 (
  set ZLIB_CMAKE_OPTS=-DCMAKE_INSTALL_PREFIX=%PREFIX% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DBUILD_SHARED_LIBS=ON -DINSTALL_MSVC_PDB=%INSTALL_PDB% -DINSTALL_PKGCONFIG_DIR=%PREFIX%/lib/pkgconfig
  call :build_package %ZLIB% "!ZLIB_CMAKE_OPTS!" & if not !STATUS! == 0 exit /b !STATUS!
)

rem ------------------------------------------------------------------------------
rem
rem PCRE

rem Check for package and switch to source folder.
rem
call :check_package_source %PCRE%

if !STATUS! == 0 (
  rem Patch CMakeLists.txt to change man page install path.
  rem
  perl -pi.bak -e ^" ^
    s~(^.+DESTINATION ^)(man^)~${1}share/${2}~; ^
    ^" CMakeLists.txt

  set PCRE_CMAKE_OPTS=-DCMAKE_INSTALL_PREFIX=%PREFIX% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DBUILD_SHARED_LIBS=ON -DPCRE_BUILD_TESTS=OFF -DPCRE_BUILD_PCRECPP=OFF -DPCRE_BUILD_PCREGREP=OFF -DPCRE_SUPPORT_PCREGREP_JIT=OFF -DPCRE_SUPPORT_UTF=ON -DPCRE_SUPPORT_UNICODE_PROPERTIES=ON -DPCRE_NEWLINE=CRLF -DINSTALL_MSVC_PDB=%INSTALL_PDB%
  call :build_package %PCRE% "!PCRE_CMAKE_OPTS!" & if not !STATUS! == 0 exit /b !STATUS!
)

rem ------------------------------------------------------------------------------
rem
rem EXPAT

rem Check for package source folder.
rem
call :check_package_source %EXPAT%

if !STATUS! == 0 (
  set EXPAT_CMAKE_OPTS=-DCMAKE_INSTALL_PREFIX=%PREFIX% -DCMAKE_BUILD_TYPE=%BUILD_TYPE%
  call :build_package %EXPAT% "!EXPAT_CMAKE_OPTS!" & if not !STATUS! == 0 exit /b !STATUS!
)

rem ------------------------------------------------------------------------------
rem
rem OPENSSL

rem Check for package and switch to source folder.
rem
call :check_package_source %OPENSSL%

if !STATUS! == 0 (
  echo. & echo Building %OPENSSL%

  if "%PLATFORM%" == "x64" (
    set OS_COMPILER=VC-WIN64A
  ) else (
    set OS_COMPILER=VC-WIN32
  )

  set OPENSSL_CONFIGURE_OPTS=--prefix=%PREFIX% --libdir=lib --openssldir=%PREFIX%\conf --with-zlib-include=%PREFIX%\include shared zlib-dynamic enable-camellia no-idea no-mdc2

  perl Configure !OS_COMPILER! !OPENSSL_CONFIGURE_OPTS! & call :get_status
  if !STATUS! == 0 (
    if exist makefile (
      if "%INSTALL_PDB%"=="OFF" (
        perl -pi.bak -e ^" ^
          s~^(INSTALL_.*PDBS=^).*~${1}nul~; ^
          ^" makefile
      )
      rem Make clean not distclean, else Makefile gets deleted.
      rem
      nmake clean 2>nul
      nmake & call :get_status
      if !STATUS! == 0 (
        nmake install & call :get_status
        if not !STATUS! == 0 (
          echo nmake install for %OPENSSL% failed with status !STATUS!
          exit /b !STATUS!
        )
      ) else (
        echo nmake for %OPENSSL% failed with status !STATUS!
        exit /b !STATUS!
      )
    ) else (
      echo Cannot find Makefile for %OPENSSL% in !SRC_DIR!
      exit /b !STATUS!
    )
  ) else (
    echo perl configure for %OPENSSL% failed with status !STATUS!
    exit /b !STATUS!
  )
)

rem ------------------------------------------------------------------------------
rem
rem LIBXML2

rem Check for package and switch to source folder.
rem
call :check_package_source %LIBXML2%

if !STATUS! == 0 (
  echo. & echo Building %LIBXML2%

  rem Build from Makefile.msvc in win32 sub-folder.
  rem
  cd /d win32

  set LIBXML2_CONFIGURE_OPTS=compiler=msvc prefix=%PREFIX% include=%PREFIX%\include lib=%PREFIX%\lib iconv=no python=no zlib=yes

  nmake /f Makefile.msvc distclean 2>nul
  cscript configure.js !LIBXML2_CONFIGURE_OPTS! & call :get_status
  if !STATUS! == 0 (
    nmake /f Makefile.msvc & call :get_status
    if !STATUS! == 0 (
      nmake /f Makefile.msvc install-dist & call :get_status
      if not !STATUS! == 0 (
        echo nmake install-dist for %LIBXML2% failed with status !STATUS!
        exit /b !STATUS!
      )
    ) else (
      echo nmake for %LIBXML2% failed with status !STATUS!
      exit /b !STATUS!
    )
  ) else (
    echo cscript configure for %LIBXML2% failed with status !STATUS!
    exit /b !STATUS!
  )
)

rem ------------------------------------------------------------------------------
rem
rem JANSSON

rem Check for package and switch to source folder.
rem
call :check_package_source %JANSSON%

if !STATUS! == 0 (
  set JANSSON_CMAKE_OPTS=-DCMAKE_INSTALL_PREFIX=%PREFIX% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DJANSSON_BUILD_SHARED_LIBS=ON -DJANSSON_BUILD_DOCS=OFF -DINSTALL_MSVC_PDB=%INSTALL_PDB% -DJANSSON_INSTALL_CMAKE_DIR=lib/cmake/jansson
  call :build_package %JANSSON% "!JANSSON_CMAKE_OPTS!" & if not !STATUS! == 0 exit /b !STATUS!
)

rem ------------------------------------------------------------------------------
rem
rem BROTLI

rem Check for package and switch to source folder.
rem
call :check_package_source %BROTLI%

if !STATUS! == 0 (
  set BROTLI_CMAKE_OPTS=-DCMAKE_INSTALL_PREFIX=%PREFIX% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DINSTALL_MSVC_PDB=%INSTALL_PDB%
  call :build_package %BROTLI% "!BROTLI_CMAKE_OPTS!" & if not !STATUS! == 0 exit /b !STATUS!
)

rem ------------------------------------------------------------------------------
rem
rem LUA

rem Check for package and switch to source folder.
rem
call :check_package_source %LUA%

if !STATUS! == 0 (
  rem Patch CMakeLists.txt to add LUA_COMPAT_ALL to compile options.
  rem
  perl -pi.bak -e ^" ^
    s~( LUA_BUILD_AS_DLL ^)(^\^)^)~${1}LUA_COMPAT_ALL ${2}~; ^
    ^" CMakeLists.txt

  set LUA_CMAKE_OPTS=-DCMAKE_INSTALL_PREFIX=%PREFIX% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DINSTALL_MSVC_PDB=%INSTALL_PDB%
  call :build_package %LUA% "!LUA_CMAKE_OPTS!" & if not !STATUS! == 0 exit /b !STATUS!
)

rem ------------------------------------------------------------------------------
rem
rem APR

rem Check for package and switch to source folder.
rem
call :check_package_source %APR%

if !STATUS! == 0 (
  rem Patch apr.hw
  rem
  perl -pi.bak -e ^" ^
    s~(#define _WIN32_WINNT ^)^.*$~${1}0x0600~; ^
    ^" include\apr.hw

  rem Patch pipe.c
  rem
  perl -pi.bak -e ^" ^
    s^{APR_FULL_BLOCK^}^{++$n == 2 ? ^"blocking^" : $^&^}ge; ^
    ^" file_io\win32\pipe.c

  rem Patch CMakeLists.txt for missing source modules.
  rem
  perl -pi.bak -e ^" ^
    s~(  atomic.+apr_atomic^)(.c^)\n~${1}${2}\n${1}64${2}\n~m; ^
    s~(  encoding.+apr_^)(escape.c^)\n~${1}${2}\n${1}encode.c\n~m; ^
    ^" CMakeLists.txt

  set APR_CMAKE_OPTS=-DCMAKE_INSTALL_PREFIX=%PREFIX% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DMIN_WINDOWS_VER=0x0600 -DAPR_HAVE_IPV6=ON -DAPR_INSTALL_PRIVATE_H=ON -DAPR_BUILD_TESTAPR=OFF -DINSTALL_PDB=%INSTALL_PDB%
  call :build_package %APR% "!APR_CMAKE_OPTS!" & if not !STATUS! == 0 exit /b !STATUS!
)

rem ------------------------------------------------------------------------------
rem
rem APR-ICONV

rem Note APR-ICONV makefiles rebuild APR since the above CMake puts the build files elsewhere.

rem Check for package and switch to source folder.
rem
call :check_package_source %APR-ICONV%

if !STATUS! == 0 (
  echo. & echo Building %APR-ICONV%

  rem Create non-version specific folder links to the APR, APR-ICONV and APR-UTIL sources.
  rem The various makefiles assume these exist.
  rem
  pushd "%BUILD_BASE%\..\src"
  mklink /d apr %APR% 1>nul 2>&1
  mklink /d apr-iconv %APR-ICONV% 1>nul 2>&1
  mklink /d apr-util %APR-UTIL% 1>nul 2>&1
  popd

  rem Copy apr.h and apr_escape_test_char.h from APR build into API source.
  rem
  copy "%BUILD_BASE%\apr\apr*.h" ".\include" 1>nul
  copy "%BUILD_BASE%\apr\apr_escape_test_char.h" "..\%APR%\include" 1>nul

  rem Choose platform options; reference as delayed expansion variables.
  rem
  if "%PLATFORM%" == "x64" (
    set BUILD_CFG=x64
    set BUILD_DIR=x64
  ) else (
    set BUILD_CFG=Win32
    set BUILD_DIR=.
  )

  rem Patch modules.mk.win for x64 Debug
  rem
  perl -pi.bak -e ^" ^
    m~(APR_SOURCE\^)\\^)(.+\\^)(Debug\\libapr-1^)~;{${2} ? $s=${2} : $s=$s}; ^
    s~(API_SOURCE\^)\\^)(Debug\\libapriconv-1^)~{$s ? ${1}.$s.${2} : $^&}~e; ^
    s~(CFG_OUTPUT  = ^)(Debug\\iconv^)~{$s ? ${1}.$s.${2} : $^&}~e; ^
    ^" build\modules.mk.win

  rmdir /s /q Debug LibD LibR Release x64 1>nul 2>&1
  nmake /f apriconv.mak CFG="apriconv - !BUILD_CFG! %BUILD_TYPE%" & call :get_status
  if not !STATUS! == 0 (
    echo nmake apriconv.mak for %APR-ICONV% failed with status !STATUS!
    exit /b !STATUS!
  )
  nmake /f libapriconv.mak CFG="libapriconv - !BUILD_CFG! %BUILD_TYPE%" & call :get_status
  if not !STATUS! == 0 (
    echo nmake libapriconv.mak for %APR-ICONV% failed with status !STATUS!
    exit /b !STATUS!
  )
  pushd ccs
  nmake /f Makefile.win BUILD_MODE="!BUILD_CFG! %BUILD_TYPE%" BIND_MODE="shared" & call :get_status
  if not !STATUS! == 0 (
    echo nmake ccs Makefile.win for %APR-ICONV% failed with status !STATUS!
    exit /b !STATUS!
  )
  popd
  pushd ces
  nmake /f Makefile.win BUILD_MODE="!BUILD_CFG! %BUILD_TYPE%" BIND_MODE="shared" & call :get_status
  if not !STATUS! == 0 (
    echo nmake ces Makefile.win for %APR-ICONV% failed with status !STATUS!
    exit /b !STATUS!
  )
  popd

  rem Manual install required with apr-iconv
  rem
  if exist "!BUILD_DIR!\LibD\apriconv-1.lib" (
    echo -- Installing: "%PREFIX%\lib\apriconv-1.lib"
    copy /b /y "!BUILD_DIR!\LibD\apriconv-1.lib" "%PREFIX%\lib" 1>nul 2>&1
  )
  if exist "!BUILD_DIR!\LibR\apriconv-1.lib" (
    echo -- Installing: "%PREFIX%\lib\apriconv-1.lib"
    copy /b /y "!BUILD_DIR!\LibR\apriconv-1.lib" "%PREFIX%\lib" 1>nul 2>&1
  )
  if exist "!BUILD_DIR!\%BUILD_TYPE%\libapriconv-1.lib" (
    echo -- Installing: "%PREFIX%\lib\libapriconv-1.lib"
    copy /b /y "!BUILD_DIR!\%BUILD_TYPE%\libapriconv-1.lib" "%PREFIX%\lib" 1>nul 2>&1
  )
  if exist "!BUILD_DIR!\%BUILD_TYPE%\libapriconv-1.dll" (
    echo -- Installing: "%PREFIX%\bin\libapriconv-1.dll"
    copy /b /y "!BUILD_DIR!\%BUILD_TYPE%\libapriconv-1.dll" "%PREFIX%\bin" 1>nul 2>&1
  )
  if exist "include\api_version.h" (
    echo -- Installing: "%PREFIX%\include\api_version.h"
    copy /b /y "include\api_version.h" "%PREFIX%\include" 1>nul 2>&1
  )
  if exist "include\apr_iconv.h" (
    echo -- Installing: "%PREFIX%\include\apr_iconv.h"
    copy /b /y "include\apr_iconv.h" "%PREFIX%\include" 1>nul 2>&1
  )
  if exist "!BUILD_DIR!\%BUILD_TYPE%\iconv" (
    echo -- Installing: "%PREFIX%\bin\iconv"
    xcopy "!BUILD_DIR!\%BUILD_TYPE%\iconv\*.so" "%PREFIX%\bin\iconv\" /c /d /i /y 1>nul 2>&1
  )
)

rem ------------------------------------------------------------------------------
rem
rem APR-UTIL

rem Check for package and switch to source folder.
rem
call :check_package_source %APR-UTIL%

if !STATUS! == 0 (
  rem Patch CMakelists.txt to support APR-ICONV if we've built it.
  rem
  if exist "%PREFIX%\lib\libapriconv-1.lib" (
    perl -pi.bak -e ^" ^
      s~^(SET.+APR_LIBRARIES[\s]+^)(\x22^)(.+libapr^)(-1.lib^)(.+ CACHE^)~${1}${2}${3}${4}${2} ${2}${3}iconv${4}${5}~; ^
      s~^(apu_have_apr_iconv_10^) 0~${1} 1~; ^
      ^" CMakeLists.txt
  )

  set APR-UTIL_CMAKE_OPTS=-DCMAKE_INSTALL_PREFIX=%PREFIX% -DOPENSSL_ROOT_DIR=%PREFIX% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DAPU_HAVE_CRYPTO=ON -DAPR_BUILD_TESTAPR=OFF -DINSTALL_PDB=%INSTALL_PDB%
  call :build_package %APR-UTIL% "!APR-UTIL_CMAKE_OPTS!" & if not !STATUS! == 0 exit /b !STATUS!
)

rem ------------------------------------------------------------------------------
rem
rem NGHTTP2

rem Check for package and switch to source folder.
rem
call :check_package_source %NGHTTP2%

if !STATUS! == 0 (
  set NGHTTP2_CMAKE_OPTS=-DCMAKE_INSTALL_PREFIX=%PREFIX% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DSTATIC_LIB_SUFFIX=_static -DENABLE_LIB_ONLY=ON
  call :build_package %NGHTTP2% "!NGHTTP2_CMAKE_OPTS!" & if not !STATUS! == 0 exit /b !STATUS!
)

rem ------------------------------------------------------------------------------
rem
rem CURL - have to build twice to get both shared and static libs.

rem Check for package and switch to source folder.
rem
call :check_package_source %CURL%

if !STATUS! == 0 (
  set CURL_CMAKE_OPTS=-DCMAKE_INSTALL_PREFIX=%PREFIX% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DCMAKE_USE_OPENSSL=OFF -DCMAKE_USE_SCHANNEL=ON -DCURL_WINDOWS_SSPI=ON -DCURL_BROTLI=ON -DUSE_NGHTTP2=ON -DENABLE_UNICODE=ON -DINSTALL_MSVC_PDB=%INSTALL_PDB% -DCURL_STATIC_CRT=OFF

  call :build_package %CURL% "!CURL_CMAKE_OPTS! -DBUILD_SHARED_LIBS=ON" & if not !STATUS! == 0 exit /b !STATUS!
  call :build_package %CURL% "!CURL_CMAKE_OPTS! -DBUILD_SHARED_LIBS=OFF" & if not !STATUS! == 0 exit /b !STATUS!
)

rem ------------------------------------------------------------------------------
rem
rem HTTPD

rem Check for package and switch to source folder.
rem
call :check_package_source %HTTPD%

if !STATUS! == 0 (
  rem Patch CMakeLists.txt to build ApacheMonitor.
  rem
  perl -pi.bak -e ^" ^
    s~(^^# ^)(.+ApacheMonitor.+^)~${2}~; ^
    ^" CMakeLists.txt

  set HTTPD_CMAKE_OPTS=-DCMAKE_INSTALL_PREFIX=%PREFIX% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DENABLE_MODULES=i -DINSTALL_PDB=%INSTALL_PDB% -DCURL_INCLUDE_DIR=%PREFIX%/include/curl -DCURL_LIBRARIES=%PREFIX%/lib/libcurl_imp.lib;%PREFIX%/lib/libcurl.lib
  call :build_package %HTTPD% "!HTTPD_CMAKE_OPTS!" & if not !STATUS! == 0 exit /b !STATUS!

  rem Install additional support scripts.
  rem
  perl -pe ^" ^
    s~#.+perlbin.+\n~~m; ^
    ^" !src_dir!\support\dbmmanage.in > %PREFIX%\bin\dbmmanage.pl

  copy !src_dir!\docs\cgi-examples\printenv %PREFIX%\cgi-bin\printenv.pl 1>nul 2>&1
)

rem ------------------------------------------------------------------------------
rem
rem MOD_FCGID

rem Check for package and switch to source folder.
rem
call :check_package_source %MOD_FCGID%

if !STATUS! == 0 (
  rem Package provides both NMake makefile and experimental CMake. We use the latter.

  set MOD_FCGID_CMAKE_OPTS=-DCMAKE_INSTALL_PREFIX=%PREFIX% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DINSTALL_PDB=NO
  call :build_package %MOD_FCGID% "!MOD_FCGID_CMAKE_OPTS!" modules\fcgid & if not !STATUS! == 0 exit /b !STATUS!
)
exit /b !STATUS!

rem ------------------------------------------------------------------------------
rem
rem Get current errorlevel value and assign it to the status variable.

:get_status
call doskey /exename=err err=%%errorlevel%%
for /f "usebackq tokens=2 delims== " %%i in (`doskey /m:err`) do (set STATUS=%%i)
exit /b !STATUS!

rem ------------------------------------------------------------------------------
rem
rem Get package and version from release variable passed as first parameter.

:get_package_details
set RELEASE=%~1
for /f "delims=-" %%i in ('echo(%RELEASE:-=^&echo(%') do call set "PACKAGE=%%RELEASE:-%%i=%%"
for %%i in (%RELEASE:-= %) do set VERSION=%%i
exit /b

rem ------------------------------------------------------------------------------
rem
rem Check package source folder exists, from release variable passed as first parameter.
rem
:check_package_source

set SRC_DIR=%BUILD_BASE%\..\src\%~1
if not exist "!SRC_DIR!" (
  echo Warning for package %~1
  echo Could not find package source folder "!SRC_DIR!"
  set STATUS=1
) else (
  cd /d "!SRC_DIR!"
  set STATUS=0
)
exit /b !STATUS!

rem ------------------------------------------------------------------------------
rem
rem Build subroutine.
rem Parameter one is the package release variable.
rem Parameter two is any required CMake options.
rem Parameter three (optional) is any package sub-folder to the CMakeLists.txt file.

:build_package

call :get_package_details %~1

rem Check source folder exists, else exit (non-fatal).

call :check_package_source %~1
if not !STATUS! == 0 (
  exit /b
) else (
  if not "%~3" == "" (
    set SRC_DIR=!SRC_DIR!\%~3
  )
)

rem Clean up any previous build.

if exist "%BUILD_BASE%\!PACKAGE!" rmdir /s /q "%BUILD_BASE%\!PACKAGE!" 1>nul 2>&1
mkdir "%BUILD_BASE%\!PACKAGE!" 1>nul 2>&1

rem Build, make and install.

if exist "%BUILD_BASE%\!PACKAGE!" (
  cd /d "%BUILD_BASE%\!PACKAGE!"
  echo. & echo Building %~1

  rem Patch CMakeLists.txt to remove debug suffix from libraries. Messes up other builds.
  rem Tried setting CMAKE_DEBUG_POSTFIX to an empty string on the CMake command line but
  rem this doesn't work with all packages, e.g. PCRE, EXPAT, etc.

  perl -pi -e ^" ^
    s~((DEBUG_POSTFIX^|POSTFIX_DEBUG^)\s+^)(\x22^)(.+^)(\x22^)~${1}${3}${5}~; ^
    ^" "!SRC_DIR!\CMakeLists.txt"

  rem Run CMake to create an NMake makefile, which we then process.

  cmake -G "NMake Makefiles" %~2 -S "!SRC_DIR!" -B . & call :get_status
  if !STATUS! == 0 (
    nmake & call :get_status
    if !STATUS! == 0 (
      nmake install & call :get_status
      if !STATUS! == 0 (
        exit /b !STATUS!
      ) else (
        echo nmake install for !PACKAGE! failed with exit status !STATUS!
        exit /b !STATUS!
      )
    ) else (
      echo nmake for !PACKAGE! failed with exit status !STATUS!
      exit /b !STATUS!
    )
  ) else (
    echo cmake for !PACKAGE! failed with exit status !STATUS!
    exit /b !STATUS!
  )
) else (
  echo Failed to make folder "%BUILD_BASE%\!PACKAGE!"
  exit /b 1
)
exit /b
Back to top
tangent



Joined: 16 Aug 2020
Posts: 39
Location: UK

PostPosted: Sun 03 Jan '21 21:05    Post subject: Reply with quote

This follow-up post covers some issues relating to building CURL, which may be of interest to Apache Lounge users, on the basis that support libraries and binaries built alongside Apache may be used for other purposes too, particularly CURL.

To deliver its various features, CURL supports a number of different SSL backends, but notably for Apache on Windows we currently need it to use Schannel (formerly WinSSL) rather than OpenSSL. This is primarily for correct operation of module mod_md.

However, features such as Proxy-HTTPS are not currently supported by Schannel, but rather depend on OpenSSL as confrmed by the CURL CMakeLists.txt file which contains the following entry:
    _add_if("HTTPS-proxy" SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS OR USE_NSS))
so it's tempting to build CURL supporting both SSL backends.

Unfortunately though, if both are present, when built with CMake, by default CURL (7.74.0 at least) appears to choose OpenSSL over Schannel, which is why for now the above CMake options for building CURL have the CMAKE_USE_OPENSSL option set to OFF.

Delving deeper into this Schannel vs OpenSSL issue, the following CURL mailing list page is of interest - https://curl.se/mail/lib-2020-07/0017.html
This describes options to tell CURL which backend SSL function to use, either by setting an environment variable or by code calling libcurl function curl_global_sslset().

Compiling a version of CURL with both OpenSSL and Schannel functions present, the environment variable method of choice produces the following:
Code:
C:\Apache24\bin>set CURL_SSL_BACKEND=schannel
C:\Apache24\bin>curl -V
curl 7.74.0 (Windows) libcurl/7.74.0 (OpenSSL/1.1.1i) Schannel zlib/1.2.11 brotli/1.0.9 nghttp2/1.42.0
Release-Date: 2020-12-09
Protocols: dict file ftp ftps gopher http https imap imaps ldap mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: AsynchDNS HTTP2 IPv6 Kerberos Largefile MultiSSL NTLM SPNEGO SSL SSPI Unicode alt-svc brotli libz

Note the HTTPS-proxy feature is missing with Schannel selected whilst Lets' Encrypt API endpoint lookups work as expected.
Code:
C:\Apache24\bin>curl https://acme-v02.api.letsencrypt.org/directory
{
  "Pll43M9mMos": "https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417",
  "keyChange": "https://acme-v02.api.letsencrypt.org/acme/key-change",
  "meta": {
    "caaIdentities": [
      "letsencrypt.org"
    ],
    "termsOfService": "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf",
    "website": "https://letsencrypt.org"
  },
  "newAccount": "https://acme-v02.api.letsencrypt.org/acme/new-acct",
  "newNonce": "https://acme-v02.api.letsencrypt.org/acme/new-nonce",
  "newOrder": "https://acme-v02.api.letsencrypt.org/acme/new-order",
  "revokeCert": "https://acme-v02.api.letsencrypt.org/acme/revoke-cert"
}

Changing the environment variable to select OpenSSL gives the following, which now details the HTTPS-Proxy feature:
Code:
C:\Apache24\bin>set CURL_SSL_BACKEND=openssl
C:\Apache24\bin>curl -V
curl 7.74.0 (Windows) libcurl/7.74.0 OpenSSL/1.1.1i (Schannel) zlib/1.2.11 brotli/1.0.9 nghttp2/1.42.0
Release-Date: 2020-12-09
Protocols: dict file ftp ftps gopher http https imap imaps ldap mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: AsynchDNS HTTP2 HTTPS-proxy IPv6 Kerberos Largefile MultiSSL NTLM SPNEGO SSL SSPI Unicode alt-svc brotli libz

However, the Lets' Encrypt API endpoint lookups no longer work (or equally any others), without allowing insecure connections (-k option):
Code:
C:\Apache24\bin>curl https://acme-v02.api.letsencrypt.org/directory
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

Hence the decision to compile CURL without OpenSSL support on Windows.
Note in both of the above, the surrounding parentheses denote the secondary SSL backend.

One would have thought on Windows CURL would favour Schannel over OpenSSL if both are present, but the code in function curl_global_sslset() (file vtls.c) shows why this isn't the case. In the absence of any specific CURL_SSL_BACKEND environment variable, the struct for *available_backends[] selects OpenSSL before Schannel.

So if OpenSSL is the selected backend, what's the reason why the Let's Encrypt API endpoint and other HTTPS lookups fail?

In practice, what appears to happen here is the OpenSSL libraries don't use the Windows native Certificate Authority (CA) store by default, and consequently fail to resolve a trusted certificate chain. Indeed, OpenSSL doesn't trust anything by default.

Digging further, the CURL developers have evidently considered this issue, and recently introduced an SSL connect option called CURLSSLOPT_NATIVE_CA, to access the Windows CA store in conjunction with the OpenSLL libraries (the following threads are of interest: https://github.com/curl/curl/pull/5585 and https://github.com/curl/curl/pull/5657). This option is mentioned in the release CHANGES file, but states it may not be present going forward.

However, there's no obvious way to set this option as a default during the build process, and since it's subject to change, it doesn't make sense to patch the code to force this option with OpenSSL connections.

So should you wish to build CURL on Windows with OpenSSL support, short of contacting the CURL developers, what options are there for Apache users?

a) build the CURL source ensuring Schannel is the default SSL backend on Windows
b) patch and build mod_md code to call curl_global_sslset() selecting Schannel over the OpenSSL default that Curl currently adopts
c) patch and build CURL to ensure on Windows OpenSSL uses the native CA store by default
d) change nothing and use the CURL_SSL_BACKEND environment variable to determine the preferred SSL backend at run time

You can see why the current view is to omit OpenSSL when building CURL.

Should you wish to make change a), this can be done by defining macro CURL_DEFAULT_SSL_BACKEND="Schannel" as a compile option at build time. Due to problems with embedded double quotes, this is easier to do with a patch to the CMakeLists.txt file, rather than trying to pass command line parameters to CMake in the build batch file. The following change to the build CURL section covers this change:
Code:
rem ------------------------------------------------------------------------------
rem
rem CURL - have to build twice to get both shared and static libs.

rem Check for package and switch to source folder.
rem
call :check_package_source %CURL%

if !STATUS! == 0 (
  set CURL_CMAKE_OPTS=-DCMAKE_INSTALL_PREFIX=%PREFIX% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DCMAKE_USE_OPENSSL=ON -DCMAKE_USE_SCHANNEL=ON -DCURL_WINDOWS_SSPI=ON -DCURL_BROTLI=ON -DUSE_NGHTTP2=ON -DENABLE_UNICODE=ON -DINSTALL_MSVC_PDB=%INSTALL_PDB% -DCURL_STATIC_CRT=OFF

  rem Patch CMakeLists.txt to add compiler defines we can't pass through the CMake command line,
  rem primarily due to Windows batch file limitations with embedded double quotes. Definitions are
  rem default SSL backend to SChannel, and set USE_TLS_SRP option.
  rem
  perl -pi.bak -e ^" ^
      s~(USE_OPENSSL ON\^)^)\n~${1} \n  add_definitions(-DCURL_DEFAULT_SSL_BACKEND=\x22schannel\x22^;-DUSE_TLS_SRP^)\n~m; ^
      ^" CMakeLists.txt

  call :build_package %CURL% "!CURL_CMAKE_OPTS! -DBUILD_SHARED_LIBS=OFF" & if not !STATUS! == 0 exit /b !STATUS!
  call :build_package %CURL% "!CURL_CMAKE_OPTS! -DBUILD_SHARED_LIBS=ON" & if not !STATUS! == 0 exit /b !STATUS!
)
Back to top
James Blond
Moderator


Joined: 19 Jan 2006
Posts: 6890
Location: Germany, Next to Hamburg

PostPosted: Tue 05 Jan '21 16:31    Post subject: Re: HOWTO: Building Apache and dependencies using CMake Reply with quote

tangent wrote:


Code:
C:\Development
   └ Apache24
      ├ src
      │   ├ apr-1.7.0
      │   ├ apr-iconv-1.2.2
      │   ├ apr-util-1.6.1
      │   ├ brotli-1.0.9
      │   ├ curl-7.74.0
      │   ├ expat-2.2.10
      │   ├ httpd-2.4.46
      │   ├ jansson-2.13.1
      │   ├ libxml2-2.9.10
      │   ├ mod_fcgid-2.3.9
      │   ├ nghttp2-1.42.0
      │   ├ openssl-1.1.1i
      │   ├ pcre-8.44
      │   └ zlib-1.2.11
      │
      └ build



Do you put lua in the src folder, too?
Back to top
tangent



Joined: 16 Aug 2020
Posts: 39
Location: UK

PostPosted: Tue 05 Jan '21 17:09    Post subject: Reply with quote

Apologies James; yes, you do. I've updated the source tree in the first post.

The batch file contains build code for LUA, but as mentioned the CMakeLists.txt file for LUA 5.3 is an extra from https://apaste.info/yOSR
Back to top


Reply to topic   Topic: HOWTO: Building Apache and dependencies using CMake View previous topic :: View next topic
Post new topic   Forum Index -> How-to's & Documentation & Tips