Add HTTPLIB_COMPILE option to Cmake (#493)

This option (default OFF) automatically splits the file (with split.py)
into a header & source file, then compiles it as a shared/static
library. This requires an installed Python v3 executable to work.

This also adds a HTTPLIB_IS_COMPILED boolean that's available after a
finfind_package(httplib) call.

Note that the minimum Cmake version increased to 3.12 because of FindPython3.
Hopefully this isn't a problem, as it's already 3 years old at this point.
This commit is contained in:
KTGH 2020-05-24 16:07:44 -04:00 committed by GitHub
parent be7962f140
commit 8cad160c0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 112 additions and 47 deletions

View File

@ -4,6 +4,9 @@
* HTTPLIB_USE_ZLIB_IF_AVAILABLE (default on) * HTTPLIB_USE_ZLIB_IF_AVAILABLE (default on)
* HTTPLIB_REQUIRE_OPENSSL (default off) * HTTPLIB_REQUIRE_OPENSSL (default off)
* HTTPLIB_REQUIRE_ZLIB (default off) * HTTPLIB_REQUIRE_ZLIB (default off)
* HTTPLIB_COMPILE (default off)
-------------------------------------------------------------------------------
After installation with Cmake, a find_package(httplib) is available. After installation with Cmake, a find_package(httplib) is available.
This creates a httplib::httplib target (if found). This creates a httplib::httplib target (if found).
@ -27,17 +30,24 @@
cmake .. cmake ..
runas /user:Administrator "cmake --build . --config Release --target install" runas /user:Administrator "cmake --build . --config Release --target install"
-------------------------------------------------------------------------------
These three variables are available after you run find_package(httplib) These three variables are available after you run find_package(httplib)
* HTTPLIB_HEADER_PATH - this is the full path to the installed header. * HTTPLIB_HEADER_PATH - this is the full path to the installed header.
* HTTPLIB_IS_USING_OPENSSL - a bool for if OpenSSL support is enabled. * HTTPLIB_IS_USING_OPENSSL - a bool for if OpenSSL support is enabled.
* HTTPLIB_IS_USING_ZLIB - a bool for if ZLIB support is enabled. * HTTPLIB_IS_USING_ZLIB - a bool for if ZLIB support is enabled.
* HTTPLIB_IS_COMPILED - a bool for if the library is header-only or compiled.
Want to use precompiled headers (Cmake feature since v3.16)? Want to use precompiled headers (Cmake feature since v3.16)?
It's as simple as doing the following (before linking): It's as simple as doing the following (before linking):
target_precompile_headers(httplib::httplib INTERFACE "${HTTPLIB_HEADER_PATH}") target_precompile_headers(httplib::httplib INTERFACE "${HTTPLIB_HEADER_PATH}")
-------------------------------------------------------------------------------
FindPython3 requires Cmake v3.12
]] ]]
cmake_minimum_required(VERSION 3.7.0 FATAL_ERROR) cmake_minimum_required(VERSION 3.12.0 FATAL_ERROR)
project(httplib LANGUAGES CXX) project(httplib LANGUAGES CXX)
# Change as needed to set an OpenSSL minimum version. # Change as needed to set an OpenSSL minimum version.
@ -51,17 +61,23 @@ option(HTTPLIB_REQUIRE_ZLIB "Requires ZLIB to be found & linked, or fails build.
# Make these options so their automatic use can be specifically disabled (as needed) # Make these options so their automatic use can be specifically disabled (as needed)
option(HTTPLIB_USE_OPENSSL_IF_AVAILABLE "Uses OpenSSL (if available) to enable HTTPS support." ON) option(HTTPLIB_USE_OPENSSL_IF_AVAILABLE "Uses OpenSSL (if available) to enable HTTPS support." ON)
option(HTTPLIB_USE_ZLIB_IF_AVAILABLE "Uses ZLIB (if available) to enable compression support." ON) option(HTTPLIB_USE_ZLIB_IF_AVAILABLE "Uses ZLIB (if available) to enable compression support." ON)
# Lets you compile the program as a regular library instead of header-only
# TODO: implement the option of option to correctly split, building, and export with the split.py script. option(HTTPLIB_COMPILE "If ON, uses a Python script to split the header into a compilable header & source file (requires Python v3)." OFF)
# option(HTTPLIB_SPLIT "Uses a Python script to split the header into a header & source file." OFF) # Defaults to static library
option(BUILD_SHARED_LIBS "Build the library as a shared library instead of static. Has no effect if using header-only." OFF)
if (BUILD_SHARED_LIBS AND WIN32 AND HTTPLIB_COMPILE)
# Necessary for Windows if building shared libs
# See https://stackoverflow.com/a/40743080
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()
# Threads needed for <thread> on some systems, and for <pthread.h> on Linux # Threads needed for <thread> on some systems, and for <pthread.h> on Linux
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
# Since Cmake v3.11, Crypto & SSL became optional when not specified as COMPONENTS.
if(HTTPLIB_REQUIRE_OPENSSL) if(HTTPLIB_REQUIRE_OPENSSL)
find_package(OpenSSL ${_HTTPLIB_OPENSSL_MIN_VER} REQUIRED) find_package(OpenSSL ${_HTTPLIB_OPENSSL_MIN_VER} COMPONENTS Crypto SSL REQUIRED)
elseif(HTTPLIB_USE_OPENSSL_IF_AVAILABLE) elseif(HTTPLIB_USE_OPENSSL_IF_AVAILABLE)
# Look quietly since it's optional are optional find_package(OpenSSL ${_HTTPLIB_OPENSSL_MIN_VER} COMPONENTS Crypto SSL QUIET)
find_package(OpenSSL ${_HTTPLIB_OPENSSL_MIN_VER} QUIET)
endif() endif()
if(HTTPLIB_REQUIRE_ZLIB) if(HTTPLIB_REQUIRE_ZLIB)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
@ -73,16 +89,53 @@ endif()
# like CMAKE_INSTALL_INCLUDEDIR or CMAKE_INSTALL_DATADIR # like CMAKE_INSTALL_INCLUDEDIR or CMAKE_INSTALL_DATADIR
include(GNUInstallDirs) include(GNUInstallDirs)
add_library(${PROJECT_NAME} INTERFACE) if(HTTPLIB_COMPILE)
# Put the split script into the build dir
configure_file(split.py "${CMAKE_CURRENT_BINARY_DIR}/split.py"
COPYONLY
)
# Needs to be in the same dir as the python script
configure_file(httplib.h "${CMAKE_CURRENT_BINARY_DIR}/httplib.h"
COPYONLY
)
# Used outside of this if-else
set(_INTERFACE_OR_PUBLIC PUBLIC)
# Brings in the Python3_EXECUTABLE path we can use.
find_package(Python3 REQUIRED)
# Actually split the file
# Keeps the output in the build dir to not pollute the main dir
execute_process(COMMAND ${Python3_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/split.py"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
ERROR_VARIABLE _httplib_split_error
)
if(_httplib_split_error)
message(FATAL_ERROR "Failed when trying to split Cpp-httplib with the Python script.\n${_httplib_split_error}")
endif()
# split.py puts output in "out"
set(_httplib_build_includedir "${CMAKE_CURRENT_BINARY_DIR}/out")
# This will automatically be either static or shared based on the value of BUILD_SHARED_LIBS
add_library(${PROJECT_NAME} "${_httplib_build_includedir}/httplib.cc")
target_sources(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${_httplib_build_includedir}/httplib.h>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/httplib.h>
)
else()
# This is for header-only.
set(_INTERFACE_OR_PUBLIC INTERFACE)
add_library(${PROJECT_NAME} INTERFACE)
set(_httplib_build_includedir "${CMAKE_CURRENT_SOURCE_DIR}")
endif()
# Lets you address the target with httplib::httplib # Lets you address the target with httplib::httplib
# Only useful if building in-tree, versus using it from an installation. # Only useful if building in-tree, versus using it from an installation.
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
# Might be missing some, but this list is somewhat comprehensive # Might be missing some, but this list is somewhat comprehensive
target_compile_features(${PROJECT_NAME} INTERFACE target_compile_features(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
cxx_std_11 cxx_std_11
cxx_nullptr cxx_nullptr
cxx_noexcept
cxx_lambdas cxx_lambdas
cxx_override cxx_override
cxx_defaulted_functions cxx_defaulted_functions
@ -94,25 +147,42 @@ target_compile_features(${PROJECT_NAME} INTERFACE
cxx_sizeof_member cxx_sizeof_member
) )
target_include_directories(${PROJECT_NAME} INTERFACE target_include_directories(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<BUILD_INTERFACE:${_httplib_build_includedir}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>) $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
target_link_libraries(${PROJECT_NAME} INTERFACE
# Always require threads
Threads::Threads
# Only link zlib & openssl if they're found
$<$<BOOL:${ZLIB_FOUND}>:ZLIB::ZLIB>
$<$<BOOL:${OPENSSL_FOUND}>:OpenSSL::SSL OpenSSL::Crypto>
) )
# Auto-define the optional support if those packages were found # Always require threads
target_compile_definitions(${PROJECT_NAME} INTERFACE target_link_libraries(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
$<$<BOOL:${ZLIB_FOUND}>:CPPHTTPLIB_ZLIB_SUPPORT> Threads::Threads
$<$<BOOL:${OPENSSL_FOUND}>:CPPHTTPLIB_OPENSSL_SUPPORT>
) )
# We check for the target when using IF_AVAILABLE since it's possible we didn't find it.
if(HTTPLIB_USE_OPENSSL_IF_AVAILABLE AND TARGET OpenSSL::SSL AND TARGET OpenSSL::Crypto OR HTTPLIB_REQUIRE_OPENSSL)
target_link_libraries(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
OpenSSL::SSL OpenSSL::Crypto
)
target_compile_definitions(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
CPPHTTPLIB_OPENSSL_SUPPORT
)
set(HTTPLIB_IS_USING_OPENSSL TRUE)
else()
set(HTTPLIB_IS_USING_OPENSSL FALSE)
endif()
# We check for the target when using IF_AVAILABLE since it's possible we didn't find it.
if(HTTPLIB_USE_ZLIB_IF_AVAILABLE AND TARGET ZLIB::ZLIB OR HTTPLIB_REQUIRE_ZLIB)
target_link_libraries(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
ZLIB::ZLIB
)
target_compile_definitions(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
CPPHTTPLIB_ZLIB_SUPPORT
)
set(HTTPLIB_IS_USING_ZLIB TRUE)
else()
set(HTTPLIB_IS_USING_ZLIB FALSE)
endif()
# Cmake's find_package search path is different based on the system # Cmake's find_package search path is different based on the system
# See https://cmake.org/cmake/help/latest/command/find_package.html for the list # See https://cmake.org/cmake/help/latest/command/find_package.html for the list
if(CMAKE_SYSTEM_NAME STREQUAL "Windows") if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
@ -144,7 +214,7 @@ install(TARGETS ${PROJECT_NAME}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
) )
install(FILES httplib.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(FILES "${_httplib_build_includedir}/httplib.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"

View File

@ -1,33 +1,28 @@
# Generates a macro to auto-configure everything # Generates a macro to auto-configure everything
@PACKAGE_INIT@ @PACKAGE_INIT@
# Setting these here so they're accessible after install.
# Might be useful for some users to check which settings were used.
set(HTTPLIB_IS_USING_OPENSSL @HTTPLIB_IS_USING_OPENSSL@)
set(HTTPLIB_IS_USING_ZLIB @HTTPLIB_IS_USING_ZLIB@)
set(HTTPLIB_IS_COMPILED @HTTPLIB_COMPILE@)
include(CMakeFindDependencyMacro) include(CMakeFindDependencyMacro)
# We add find_dependency calls here to not make the end-user have to call them. # We add find_dependency calls here to not make the end-user have to call them.
find_dependency(Threads REQUIRED) find_dependency(Threads REQUIRED)
if(@HTTPLIB_REQUIRE_OPENSSL@) if(@HTTPLIB_IS_USING_OPENSSL@)
find_dependency(OpenSSL @_HTTPLIB_OPENSSL_MIN_VER@ REQUIRED) # OpenSSL COMPONENTS were added in Cmake v3.11
# Lets you check if these options were correctly enabled for your install if(CMAKE_VERSION VERSION_LESS "3.11")
set(HTTPLIB_IS_USING_OPENSSL TRUE) find_dependency(OpenSSL @_HTTPLIB_OPENSSL_MIN_VER@ REQUIRED)
elseif(@HTTPLIB_USE_OPENSSL_IF_AVAILABLE@) else()
# Look quietly since it's optional # Once the COMPONENTS were added, they were made optional when not specified.
find_dependency(OpenSSL @_HTTPLIB_OPENSSL_MIN_VER@ QUIET) # Since we use both, we need to search for both.
# Lets you check if these options were correctly enabled for your install find_dependency(OpenSSL @_HTTPLIB_OPENSSL_MIN_VER@ COMPONENTS Crypto SSL REQUIRED)
set(HTTPLIB_IS_USING_OPENSSL @OPENSSL_FOUND@) endif()
else()
set(HTTPLIB_IS_USING_OPENSSL FALSE)
endif() endif()
if(@HTTPLIB_REQUIRE_ZLIB@) if(@HTTPLIB_IS_USING_ZLIB@)
find_dependency(ZLIB REQUIRED) find_dependency(ZLIB REQUIRED)
# Lets you check if these options were correctly enabled for your install
set(HTTPLIB_IS_USING_ZLIB TRUE)
elseif(@HTTPLIB_USE_ZLIB_IF_AVAILABLE@)
# Look quietly since it's optional
find_dependency(ZLIB QUIET)
# Lets you check if these options were correctly enabled for your install
set(HTTPLIB_IS_USING_ZLIB @ZLIB_FOUND@)
else()
set(HTTPLIB_IS_USING_ZLIB FALSE)
endif() endif()
# Lets the end-user find the header path if needed # Lets the end-user find the header path if needed