diff --git a/CMake.md b/CMake.md new file mode 100644 index 000000000..f2e92f7e7 --- /dev/null +++ b/CMake.md @@ -0,0 +1,100 @@ +# Building zlib with CMake # + +## Prerequisites ## + +CMake version 2.4.4 or later is required. [Download](https://cmake.org/download/) and install the latest CMake (recommended). + +## Introduction ## + +If you are not familiar with CMake, this project is a great way to learn how it works. Let's define a couple directories we'll refer to throughout the document: + +- `BUILDDIR` is the directory where the build takes place +- `BUILDTYPE` is one of the CMake standard build types: `Debug`, `RelWithDebInfo`, or `Release`. +- `INSTDIR` is the directory where the build result is installed +- `SRCDIR` is the directory that contains the zlib project files + +CMake takes cmake script files (typically called CMakeLists.txt) from `SRCDIR` and generates an entire platform-specific build environment in `BUILDDIR`. CMake supports output of many different build environments, such as make, ninja, and NMake to name a few. CMake also supports generation of IDE projects for Eclipse, Visual Studio, and others. + +## Invocation ## + +Generating an out-of-tree build directory with CMake is trivial: + +1. Create the `BUILDDIR`. +2. cd into `BUILDDIR`. +3. cmake `SRCDIR` `-DCMAKE_INSTALL_PREFIX=INSTDIR` `` + +## Options ## + +Options are defined when you generate the build environment. Options are defined by passing them with a `-D` prefix on the cmake command line. Here are the options that matter most when building zlib: + +| Option | Origin | Default | Meaning | +| :----- | -----: | ------: | :------ | +| `ASM686` | zlib | `OFF` | Build with an i686 assembly implementation | +| `AMD64` | zlib | `OFF` | Build with an x86_64 assembly implementation | +| `BUILD_SHARED_LIBS` | cmake | `ON` | Build a shared library | +| `BUILD_STATIC_AND_SHARED` | zlib | `ON` | Build both a shared and a static library* | +| `CMAKE_BUILD_TYPE` | cmake | `Debug` | Defines the build type at generation time** | +| `CMAKE_INSTALL_PREFIX` | cmake | depends | Build prefix for installation, platform specific| +| `SKIP_INSTALL_ALL` | zlib | `OFF` | Skip installation of everything | +| `SKIP_INSTALL_FILES` | zlib | `OFF` | Skip installation of manual pages and pkgconfig files | +| `SKIP_INSTALL_HEADERS` | zlib | `OFF` | Skip installation of headers | +| `SKIP_INSTALL_LIRARIES` | zlib | `OFF` | Skip installation of binaries, libraries, and symbol files | + +\* The CMake build for zlib produces static and shared libraries in the same build by default. This behavior is not always optimal for building on every platform, therefore a CMake option called `BUILD_STATIC_AND_SHARED` was introduced to allow the caller to disable this combined build and honor the more commonly used `BUILD_SHARED_LIBS` CMake option instead. + +\** `CMAKE_BUILD_TYPE` is only used on Unix. For Windows, the build type is defined at build time, not at generation time. + +A default build without options will create a shared library, debug build, and attempt to install it into a system-wide visible location (`/usr/local` on Unix, and `C:\Program Files` on Windows). + +## Unix ## + +Unix does not suffer from as many runtime library choices as Windows, and is therefore quite simple. Using a minimal set of options we end up with static and shared builds as output: + + $ mkdir + $ cd + $ cmake -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE= + $ cmake --build . --target install + +### Generating Eclipse Projects ### + +CMake has the ability to generate Eclipse projects. When invoking cmake in `BUILDDIR`, specify the generator: + + $ cmake `` -G"Eclipse CDT4 - Unix Makefiles" + +This will produce an Eclipse solution targeting `make` builds. A full list of generators can be obtained by running this command and scrolling to the end of the output: + + cmake --help + +## Windows ## + +Building on Windows, with the large number of library configuration options, is a little more complicated. For example one can build a statically-linked zlib that uses a dynamic runtime library, or one can build a statically-linked zlib that uses a static MSVC runtime library. The CMake install target will put only the files you need into `INSTDIR`. If the build contains debugging information, that will be included. Some examples for building on Windows are found below. + +### DLL (shared) with MSVCRT DLL ### + + C:\BUILDDIR> cmake C:\SRCDIR -DCMAKE_INSTALL_PREFIX= -DBUILD_STATIC_AND_SHARED=OFF + C:\BUILDDIR> cmake --build . --target install --config + +### LIB (static) with MSVCRT LIB (statically linked runtime) ### + + C:\BUILDDIR> cmake C:\SRCDIR -DCMAKE_INSTALL_PREFIX= -DBUILD_STATIC_AND_SHARED=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_C_FLAGS_="/MT /Z7" + C:\BUILDDIR> cmake --build . --target install --config + +Note the use of `CMAKE_C_FLAGS_` here, which is equivalent to using `CFLAGS` in a make build for a given `BUILDTYPE`. Options typically used here are: + +- `/MT` to force a static release runtime link +- `/MTd` to force a static debug runtime link +- `/Z7` to put symbols in objects and libraries instead of a PDB file + +### Generating Visual Studio Projects ### + +CMake has the ability to generate MSVC projects. When invoking cmake in `BUILDDIR`, specify the generator: + + C:\TEMP\zlib-build> cmake C:\SRC\zlib -G"Visual Studio 15 2017 Win64" + +This will produce a Visual Studio 2017 solution. A full list of generators can be obtained by running this command and scrolling to the end of the output: + + cmake --help + +### Additional Resources ### + +A full suite of example builds for Windows can be found in the `win32\cmake-matrix.bat` file. \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 0fe939df6..cd1cdb329 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,16 @@ set(VERSION "1.2.11") option(ASM686 "Enable building i686 assembly implementation") option(AMD64 "Enable building amd64 assembly implementation") +option(BUILD_SHARED_LIBS "Build shared (dynamic) libraries instead of static" ON) +option(BUILD_STATIC_AND_SHARED "Build both static and shared libraries in the same build" ON) +option(SKIP_INSTALL_ALL "Skip installation of everything") +option(SKIP_INSTALL_FILES "Skip installation of manual pages and pkgconfig files") +option(SKIP_INSTALL_HEADERS "Skip installation of headers") +option(SKIP_INSTALL_LIBRARIES "Skip installation of binaries, libraries, and symbol files") + +if(BUILD_STATIC_AND_SHARED) + set(BUILD_SHARED_LIBS ON) +endif() set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables") set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries") @@ -80,9 +90,9 @@ endif() set(ZLIB_PC ${CMAKE_CURRENT_BINARY_DIR}/zlib.pc) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zlib.pc.cmakein - ${ZLIB_PC} @ONLY) -configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.cmakein - ${CMAKE_CURRENT_BINARY_DIR}/zconf.h @ONLY) + ${ZLIB_PC} @ONLY) +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.cmakein + ${CMAKE_CURRENT_BINARY_DIR}/zconf.h @ONLY) include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}) @@ -123,7 +133,7 @@ set(ZLIB_SRCS zutil.c ) -if(NOT MINGW) +if(BUILD_SHARED_LIBS AND NOT MINGW) set(ZLIB_DLL_SRCS win32/zlib1.rc # If present will override custom build rule below. ) @@ -136,30 +146,30 @@ if(CMAKE_COMPILER_IS_GNUCC) set(ZLIB_ASMS contrib/amd64/amd64-match.S) endif () - if(ZLIB_ASMS) - add_definitions(-DASMV) - set_source_files_properties(${ZLIB_ASMS} PROPERTIES LANGUAGE C COMPILE_FLAGS -DNO_UNDERLINE) - endif() + if(ZLIB_ASMS) + add_definitions(-DASMV) + set_source_files_properties(${ZLIB_ASMS} PROPERTIES LANGUAGE C COMPILE_FLAGS -DNO_UNDERLINE) + endif() endif() if(MSVC) if(ASM686) - ENABLE_LANGUAGE(ASM_MASM) + ENABLE_LANGUAGE(ASM_MASM) set(ZLIB_ASMS - contrib/masmx86/inffas32.asm - contrib/masmx86/match686.asm - ) + contrib/masmx86/inffas32.asm + contrib/masmx86/match686.asm + ) elseif (AMD64) - ENABLE_LANGUAGE(ASM_MASM) + ENABLE_LANGUAGE(ASM_MASM) set(ZLIB_ASMS - contrib/masmx64/gvmat64.asm - contrib/masmx64/inffasx64.asm - ) + contrib/masmx64/gvmat64.asm + contrib/masmx64/inffasx64.asm + ) endif() - if(ZLIB_ASMS) - add_definitions(-DASMV -DASMINF) - endif() + if(ZLIB_ASMS) + add_definitions(-DASMV -DASMINF) + endif() endif() # parse the full version number from zlib.h and include in ZLIB_FULL_VERSION @@ -167,7 +177,7 @@ file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents) string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*" "\\1" ZLIB_FULL_VERSION ${_zlib_h_contents}) -if(MINGW) +if(BUILD_SHARED_LIBS AND MINGW) # This gets us DLL resource information when compiling on MinGW. if(NOT CMAKE_RC_COMPILER) set(CMAKE_RC_COMPILER windres.exe) @@ -181,48 +191,112 @@ if(MINGW) -o ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zlib1.rc) set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) -endif(MINGW) - -add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) -add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) -set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL) -set_target_properties(zlib PROPERTIES SOVERSION 1) +endif() -if(NOT CYGWIN) - # This property causes shared libraries on Linux to have the full version - # encoded into their final filename. We disable this on Cygwin because - # it causes cygz-${ZLIB_FULL_VERSION}.dll to be created when cygz.dll - # seems to be the default. - # - # This has no effect with MSVC, on that platform the version info for - # the DLL comes from the resource file win32/zlib1.rc - set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION}) +if(BUILD_STATIC_AND_SHARED) + # This preserves the original behavior of the zlib cmake build, however combining shared and static + # builds does not afford customization of compiler options typically used on some platforms for each type + add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) + add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +else() + # Use BUILD_SHARED_LIBS to control whether the result is shared or static like any other typical cmake build + add_library(zlib ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) endif() if(UNIX) # On unix-like platforms the library is almost always called libz - set_target_properties(zlib zlibstatic PROPERTIES OUTPUT_NAME z) - if(NOT APPLE) - set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"") - endif() -elseif(BUILD_SHARED_LIBS AND WIN32) - # Creates zlib1.dll when building shared library version - set_target_properties(zlib PROPERTIES SUFFIX "1.dll") + set_target_properties(zlib PROPERTIES OUTPUT_NAME z) + if(BUILD_STATIC_AND_SHARED) + set_target_properties(zlibstatic PROPERTIES OUTPUT_NAME z) + endif() endif() -if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) - install(TARGETS zlib zlibstatic +if(BUILD_SHARED_LIBS) + message(STATUS "Building shared (dynamic) library") + set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL) + set_target_properties(zlib PROPERTIES SOVERSION 1) + + if(NOT CYGWIN) + # This property causes shared libraries on Linux to have the full version + # encoded into their final filename. We disable this on Cygwin because + # it causes cygz-${ZLIB_FULL_VERSION}.dll to be created when cygz.dll + # seems to be the default. + # + # This has no effect with MSVC, on that platform the version info for + # the DLL comes from the resource file win32/zlib1.rc + set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION}) + endif() + + if (UNIX AND NOT APPLE) + set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"") + endif() + + if(WIN32) + # Creates zlib1.dll when building shared library version + set_target_properties(zlib PROPERTIES SUFFIX "1.dll") + endif() +endif() + +if(BUILD_STATIC_AND_SHARED OR NOT BUILD_SHARED_LIBS) + message(STATUS "Building static library") +endif() + +if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL) + install(FILES ${ZLIB_PUBLIC_HDRS} DESTINATION "${INSTALL_INC_DIR}") +endif() +if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL) + install(TARGETS zlib RUNTIME DESTINATION "${INSTALL_BIN_DIR}" ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" LIBRARY DESTINATION "${INSTALL_LIB_DIR}" ) + if(BUILD_STATIC_AND_SHARED) + install(TARGETS zlibstatic + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" + ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" ) + endif() + + # This entire block is just for handling the PDB file properly! + # It is all OPTIONAL because there is no way to test and see if + # "/Zi" or "/ZI" was used in the build process. + if(MSVC) + if(BUILD_SHARED_LIBS) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Debug/zlibd.pdb" + CONFIGURATIONS Debug + DESTINATION "${INSTALL_BIN_DIR}" + RENAME "zlibd1.pdb" + OPTIONAL) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/zlib.pdb" + CONFIGURATIONS RelWithDebInfo + DESTINATION "${INSTALL_BIN_DIR}" + RENAME "zlib1.pdb" + OPTIONAL) + endif() + if(BUILD_STATIC_AND_SHARED) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zlibstatic.dir/Debug/zlibstatic.pdb" + CONFIGURATIONS Debug + DESTINATION "${INSTALL_LIB_DIR}" + RENAME "zlibstaticd.pdb" + OPTIONAL) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zlibstatic.dir/RelWithDebInfo/zlibstatic.pdb" + CONFIGURATIONS RelWithDebInfo + DESTINATION "${INSTALL_LIB_DIR}" + OPTIONAL) + elseif(NOT BUILD_SHARED_LIBS) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zlib.dir/Debug/zlib.pdb" + CONFIGURATIONS Debug + DESTINATION "${INSTALL_LIB_DIR}" + RENAME "zlibd.pdb" + OPTIONAL) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zlib.dir/RelWithDebInfo/zlib.pdb" + CONFIGURATIONS RelWithDebInfo + DESTINATION "${INSTALL_LIB_DIR}" + OPTIONAL) + endif() + endif() endif() -if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL ) - install(FILES ${ZLIB_PUBLIC_HDRS} DESTINATION "${INSTALL_INC_DIR}") -endif() -if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) +if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL) install(FILES zlib.3 DESTINATION "${INSTALL_MAN_DIR}/man3") -endif() -if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) install(FILES ${ZLIB_PC} DESTINATION "${INSTALL_PKGCONFIG_DIR}") endif() diff --git a/win32/cmake-matrix.bat b/win32/cmake-matrix.bat new file mode 100644 index 000000000..6b9f37d09 --- /dev/null +++ b/win32/cmake-matrix.bat @@ -0,0 +1,57 @@ +:: +:: Builds many different combinations of zlib on windows. +:: Provided as an example on how to build exactly what you want. +:: + +@ECHO ON +SETLOCAL EnableDelayedExpansion + +:: +:: Set these to your BUILDDIR, INSTDIR, and SRCDIR if needed - the +:: defaults should work fine if you run the batch script from win32. +:: The LOGFILE will receive directory listings from each build combo. +:: + +SET ZLIB_BUILD=C:\temp\zlib\zlib-build +SET ZLIB_INSTALL=C:\temp\zlib\zlib-install +SET ZLIB_HOME=%CD%\.. +SET LOGFILE=C:\temp\zlib\zlib-matrix.log +@ECHO/ > %LOGFILE% + +:: These are the stock builds for zlib (builds static and shared together) +CALL :BUILDONE Debug stock-debug +CALL :BUILDONE RelWithDebInfo stock-relwithdebinfo +CALL :BUILDONE Release stock-release + +:: These are new build configurations targeting a single type and mode +CALL :BUILDONE Debug shared-debug "-DBUILD_STATIC_AND_SHARED=OFF" +CALL :BUILDONE RelWithDebInfo shared-relwithdebinfo "-DBUILD_STATIC_AND_SHARED=OFF" +CALL :BUILDONE Release shared-release "-DBUILD_STATIC_AND_SHARED=OFF" + +:: For static debug library builds put the debug information in the library with /Z7 +CALL :BUILDONE Debug static-debug "-DBUILD_STATIC_AND_SHARED=OFF" "-DBUILD_SHARED_LIBS=OFF" "-DCMAKE_C_FLAGS_DEBUG=/Z7" +CALL :BUILDONE RelWithDebInfo static-relwithdebinfo "-DBUILD_STATIC_AND_SHARED=OFF" "-DBUILD_SHARED_LIBS=OFF" "-DCMAKE_C_FLAGS_RELWITHDEBINFO=/Z7" +CALL :BUILDONE Release static-release "-DBUILD_STATIC_AND_SHARED=OFF" "-DBUILD_SHARED_LIBS=OFF" + +:: Static library with a static MSVC runtime: +CALL :BUILDONE Debug static-debug-static-rtl "-DBUILD_STATIC_AND_SHARED=OFF" "-DBUILD_SHARED_LIBS=OFF" "-DCMAKE_C_FLAGS_DEBUG=/MTd /Z7" +CALL :BUILDONE RelWithDebInfo static-relwithdebinfo-static-rtl "-DBUILD_STATIC_AND_SHARED=OFF" "-DBUILD_SHARED_LIBS=OFF" "-DCMAKE_C_FLAGS_RELWITHDEBINFO=/MT /Z7" +CALL :BUILDONE Release static-release-static-rtl "-DBUILD_STATIC_AND_SHARED=OFF" "-DBUILD_SHARED_LIBS=OFF" "-DCMAKE_C_FLAGS_RELEASE=/MT" + +EXIT /B + +:: \param[in] %1 Build Config +:: \param[in] %2 Build Name +:: \param[in] %3.. Build Options +:BUILDONE +IF EXIST %ZLIB_BUILD%\%2 (RMDIR /S /Q %ZLIB_BUILD%\%2) +IF EXIST %ZLIB_INSTALL%\%2 (RMDIR /S /Q %ZLIB_INSTALL%\%2) +MKDIR %ZLIB_BUILD%\%2 +CD %ZLIB_BUILD%\%2 +cmake %ZLIB_HOME% -DCMAKE_INSTALL_PREFIX=%ZLIB_INSTALL%\%2 %3 %4 %5 %6 %7 || EXIT /B +cmake --build . --target install --config %1 +@ECHO/ >> %LOGFILE% +@ECHO "-------------------------------------------------------------------------------" >> %LOGFILE% +@ECHO "-- %2" >> %LOGFILE% +@ECHO "-------------------------------------------------------------------------------" >> %LOGFILE% +DIR /S %ZLIB_INSTALL%\%2 >> %LOGFILE%