From c81968d3a7c16be0be4cb4f79a7dedfd90d8ae1d Mon Sep 17 00:00:00 2001 From: Micah Snyder Date: Wed, 18 Nov 2020 21:19:27 -0800 Subject: [PATCH] GitHub Actions testing on Ubuntu, Mac, & Windows Updates to fix issues in the CMake install instructions. Updates the README.md to indicate that CMake is now preferred Adds a GitHub Actions badge, Discord badge, and logo to the README.md. CMake: - Renamed ENABLE_DOCS to ENABLE_MAN_PAGES. - Fixed build issue when milter isn't enabled on Linux. Changed the default to build milter on non-macOS, non-Windows operating systems. - Fix LD_LIBRARY_PATH for tests including on macOS where LD_LIBRARY_PATH and DYLD_LIBRARY_PATH must be manually propagated to subprocesses. - Use UNKNOWN IMPORTED library instead of INTERFACE IMPORTED library for pdcurses, but still use INTERFACE IMPORTED for ncurses. UNKNOWN IMPORTED appears to be required so that we can use $ to collected the pdcurses library at install time on Windows. - When building with vcpkg on Windows, CMake will automatically install your app local dependencies (aka the DLL runtime dependencies). Meanwhile, file(GET_RUNTIME_DEPENDENCIES ...) doesn't appear to work correctly with vcpkg packages. The solution is to use a custom target that has CMake perform a local install to the unit_tests directory when using vcpkg. This is in fact far easier than using GET_RUNTIME_DEPENDENCIES in the unit_tests for assembling the test environment but we can't use this method for the non-vcpkg install because it won't collect checkDynamic.dll for us because we don't install our tests. We also can't link with the static check.lib because the static check.lib has pthreads symbols linked in and will conflict with our pthread.dll. TL;DR: We'll continue to use file(GET_RUNTIME_DEPENDENCIES ...) for assembling the test enviornment on non-vcpkg builds, and use the local install method for vcpkg builds. testcase.py: Wrapped a Pathlib.unlink() call in exception handling as the missing_ok optional parameter requires a Python version too new for common use. Remove localtime_r from win32 compat lib. localtime_r may be present in libcheck when building with vcpkg and while making it a static function would also solve the issue, using localtime_s instead like we do everywhere else should work just fine. check_clamd: Limited the max # of connections for the stress test on Mac to 850, to address issues found testing on macos-latest on GitHub Actions. --- .github/workflows/cmake.yml | 173 +++++++++++++ CMakeLists.txt | 81 +++--- CMakeOptions.cmake | 8 +- INSTALL.cmake.md | 501 +++++++++++++++++++++--------------- README.md | 56 ++-- cmake/FindCURSES.cmake | 4 +- docs/CMakeLists.txt | 140 +++++----- logo.png | Bin 0 -> 25476 bytes unit_tests/CMakeLists.txt | 239 +++++++++-------- unit_tests/check_clamd.c | 23 +- unit_tests/clamd_test.py | 12 +- unit_tests/testcase.py | 15 +- win32/compat/strptime.c | 11 +- 13 files changed, 805 insertions(+), 458 deletions(-) create mode 100644 .github/workflows/cmake.yml create mode 100644 logo.png diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml new file mode 100644 index 0000000000..2c9d28503f --- /dev/null +++ b/.github/workflows/cmake.yml @@ -0,0 +1,173 @@ +name: CMake Build + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + push: + branches: + - rel/* + - dev/* + - main + pull_request: + branches: + - rel/* + - dev/* + - main + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + VCPKG_GIT_REF: 8a9a97315aefb3f8bc5d81bf66ca0025938b9c91 + +jobs: + build-windows: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v1 + + - name: Install Build Tools + uses: crazy-max/ghaction-chocolatey@v1 + with: + args: install wixtoolset + + - uses: lukka/get-cmake@latest + + # Restore from cache the previously built ports. If cache-miss, download, build vcpkg ports. + - name: Restore vcpkg ports from cache or install vcpkg + # Download and build vcpkg, without installing any port. If content is cached already, it is a no-op. + uses: lukka/run-vcpkg@v5 + id: runvcpkg + with: + vcpkgArguments: "curl[openssl] json-c libxml2 pcre2 check pthreads zlib pdcurses bzip2" + vcpkgGitCommitId: "${{ env.VCPKG_GIT_REF }}" + vcpkgTriplet: "x64-windows" + + - name: Print the VCPKG_ROOT & VCPKG_TRIPLET (for debugging) + shell: bash + run: echo "'${{ steps.runvcpkg.outputs.RUNVCPKG_VCPKG_ROOT_OUT }}' '${{ steps.runvcpkg.outputs.RUNVCPKG_VCPKG_TRIPLET_OUT }}' " + + - name: dir the VCPKG_ROOT + run: dir ${{ steps.runvcpkg.outputs.RUNVCPKG_VCPKG_ROOT_OUT }} + + - name: Create Build Directory + shell: bash + # Some projects don't allow in-source building, so create a separate build directory + # We'll use this as our working directory for all subsequent commands + run: cmake -E make_directory ${{runner.workspace}}/build + + - name: Run CMake+Ninja with triplet (cmd) + uses: lukka/run-cmake@main + id: runcmake_cmd + with: + cmakeGenerator: "Ninja" # Visual Studio 15 2017 + cmakeListsOrSettingsJson: "CMakeListsTxtBasic" + cmakeListsTxtPath: "${{runner.workspace}}/clamav-devel/CMakeLists.txt" + useVcpkgToolchainFile: true + cmakeAppendedArgs: '-A x64 -DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" -DENABLE_EXAMPLES=ON -DENABLE_STATIC_LIB=ON -- -v' + cmakeBuildType: "${{ env.BUILD_TYPE }}" + vcpkgTriplet: ${{ steps.runvcpkg.outputs.RUNVCPKG_VCPKG_TRIPLET_OUT }} + buildDirectory: "${{runner.workspace}}/build" + + - name: Test + working-directory: ${{runner.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{ env.BUILD_TYPE }} -V + + - name: Create Installer + working-directory: ${{runner.workspace}}/build + run: cpack -C ${{ env.BUILD_TYPE }} + + build-macos: + runs-on: macos-latest + + steps: + - uses: actions/checkout@v1 + + - name: Install Build Tools + run: brew install bison flex + + - name: Install Dependencies + run: brew install bzip2 check curl-openssl json-c libxml2 ncurses openssl@1.1 pcre2 zlib + + - uses: lukka/get-cmake@latest + + - name: Create Build Directory + shell: bash + # Some projects don't allow in-source building, so create a separate build directory + # We'll use this as our working directory for all subsequent commands + run: cmake -E make_directory ${{runner.workspace}}/build + + - name: Configure CMake + # Use a bash shell so we can use the same syntax for environment variable + # access regardless of the host operating system + working-directory: ${{runner.workspace}}/build + # Note the current convention is to use the -S and -B options here to specify source + # and build directories, but this is only available with CMake 3.13 and higher. + # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 + run: + cmake ${{runner.workspace}}/clamav-devel -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} + -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl@1.1/ + -DOPENSSL_CRYPTO_LIBRARY=/usr/local/opt/openssl@1.1/lib/libcrypto.1.1.dylib + -DOPENSSL_SSL_LIBRARY=/usr/local/opt/openssl@1.1/lib/libssl.1.1.dylib + -DENABLE_STATIC_LIB=ON + -DENABLE_EXAMPLES=ON + + - name: Build + shell: bash + working-directory: ${{runner.workspace}}/build + # Execute the build. You can specify a specific target with "--target " + run: cmake --build . --config ${{ env.BUILD_TYPE }} + + - name: Test + shell: bash + working-directory: ${{runner.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{ env.BUILD_TYPE }} -V + + build-ubuntu: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + + - name: Install Build Tools + run: sudo apt-get install -y bison flex valgrind + + - name: Install Dependencies + run: sudo apt-get install -y check libbz2-dev libcurl4-openssl-dev libjson-c-dev libmilter-dev libncurses5-dev libpcre3-dev libssl-dev libxml2-dev zlib1g-dev + + - uses: lukka/get-cmake@latest + + - name: Create Build Directory + shell: bash + # Some projects don't allow in-source building, so create a separate build directory + # We'll use this as our working directory for all subsequent commands + run: cmake -E make_directory ${{runner.workspace}}/build + + - name: Configure CMake + # Use a bash shell so we can use the same syntax for environment variable + # access regardless of the host operating system + working-directory: ${{runner.workspace}}/build + # Note the current convention is to use the -S and -B options here to specify source + # and build directories, but this is only available with CMake 3.13 and higher. + # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 + run: + cmake ${{runner.workspace}}/clamav-devel -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} + -DENABLE_STATIC_LIB=ON + -DENABLE_EXAMPLES=ON + + - name: Build + shell: bash + working-directory: ${{runner.workspace}}/build + # Execute the build. You can specify a specific target with "--target " + run: cmake --build . --config ${{ env.BUILD_TYPE }} + + - name: Test + shell: bash + working-directory: ${{runner.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{ env.BUILD_TYPE }} -V diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b99d8f57b..27d068d0e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,13 @@ math(EXPR LIBFRESHCLAM_SOVERSION "${LIBFRESHCLAM_CURRENT} - ${LIBFRESHCLAM_AGE}" set(LIBFRESHCLAM_VERSION "${LIBFRESHCLAM_SOVERSION}.${LIBFRESHCLAM_AGE}.${LIBFRESHCLAM_REVISION}") HexVersion(LIBFRESHCLAM_VERSION_NUM ${LIBFRESHCLAM_CURRENT} ${LIBFRESHCLAM_REVISION} ${LIBFRESHCLAM_AGE}) +# +# Define C_LINUX because CMake only defines UNIX +# +if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + set(C_LINUX 1) +endif() + # Git optionally used to add commit info into build to differentiate in bug reports. find_package(Git) if(Git_FOUND) @@ -79,19 +86,27 @@ endif() # # CMake Option default values: -set(ENABLE_APP_DEFAULT ON) -set(ENABLE_MILTER_DEFAULT OFF) -set(ENABLE_CLAMONACC_DEFAULT ON) -set(ENABLE_EXAMPLES_DEFAULT OFF) -set(ENABLE_TESTS_DEFAULT ON) +set(ENABLE_APP_DEFAULT ON) +if(WIN32 OR APPLE) + set(ENABLE_MILTER_DEFAULT OFF) +else() + set(ENABLE_MILTER_DEFAULT ON) +endif() +if(C_LINUX) + set(ENABLE_CLAMONACC_DEFAULT ON) +else() + set(ENABLE_CLAMONACC_DEFAULT OFF) +endif() +set(ENABLE_EXAMPLES_DEFAULT OFF) +set(ENABLE_TESTS_DEFAULT ON) if(WIN32) - set(ENABLE_DOCS_DEFAULT OFF) + set(ENABLE_MAN_PAGES_DEFAULT OFF) else() - set(ENABLE_DOCS_DEFAULT ON) + set(ENABLE_MAN_PAGES_DEFAULT ON) endif() -set(ENABLE_DOXYGEN_DEFAULT OFF) -set(ENABLE_UNRAR_DEFAULT ON) -set(ENABLE_SYSTEMD_DEFAULT ON) +set(ENABLE_DOXYGEN_DEFAULT OFF) +set(ENABLE_UNRAR_DEFAULT ON) +set(ENABLE_SYSTEMD_DEFAULT ON) # See CMakeOptions.cmake for additional options. include(CMakeOptions.cmake) @@ -127,8 +142,8 @@ else() set(ENABLE_LIB_ONLY_DISABLED_OTHERS 0) endif() if(ENABLE_LIBCLAMAV_ONLY) - set(ENABLE_APP OFF) - set(ENABLE_EXAMPLES OFF) + set(ENABLE_APP OFF) + set(ENABLE_EXAMPLES OFF) endif() # @@ -139,26 +154,14 @@ if(APPLE) endif() set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") -# -# Define C_LINUX because CMake only defines UNIX -# -if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") - set(C_LINUX 1) - +if(C_LINUX) if(CMAKE_COMPILER_IS_GNUCXX) - # For O_LARGEFILE, O_CLOEXEC, O_DIRECTORY, O_NOFOLLOW, etc flags on older systems + # Set _GNU_SOURCE for O_LARGEFILE, O_CLOEXEC, O_DIRECTORY, O_NOFOLLOW, etc flags on older systems # (pre POSIX.1-2008: glibc 2.11 and earlier). #4042 set(_GNU_SOURCE 1) endif() endif() -# -# Set FreeBSD include path to include /usr/local/include -# -if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") - include_directories(/usr/local/include) -endif() - # # Use the `lib` prefix on Windows, to match previous ClamAV build # @@ -733,7 +736,7 @@ endif() add_subdirectory( libclamunrar_iface ) if(NOT ENABLE_EXTERNAL_MSPACK) - add_subdirectory(libclammspack) + add_subdirectory( libclammspack ) else() find_package(MSPack) endif() @@ -761,7 +764,7 @@ if(NOT ENABLE_LIBCLAMAV_ONLY) add_subdirectory( clamonacc ) endif() - if(NOT WIN32 AND ENABLE_MILTER) + if(ENABLE_MILTER) add_subdirectory( clamav-milter ) endif() @@ -792,13 +795,11 @@ endif() include(CTest) add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}) if(ENABLE_TESTS) - add_subdirectory(test) - add_subdirectory(unit_tests) + add_subdirectory( test ) + add_subdirectory( unit_tests ) endif() -if(ENABLE_DOCS) - add_subdirectory( docs ) -endif() +add_subdirectory( docs ) if(ENABLE_FUZZ) add_subdirectory( fuzz ) @@ -814,6 +815,7 @@ ${c} Package Version: ${e}${PACKAGE_STRING} ${c} libclamav version: ${e}${LIBCLAMAV_CURRENT}:${LIBCLAMAV_REVISION}:${LIBCLAMAV_AGE} ${c} libfreshclam version: ${e}${LIBFRESHCLAM_CURRENT}:${LIBFRESHCLAM_REVISION}:${LIBFRESHCLAM_AGE} ${c} Install prefix: ${e}${CMAKE_INSTALL_PREFIX} +${c} Host system: ${e}${CMAKE_HOST_SYSTEM} ${c} Target system: ${e}${CMAKE_SYSTEM} ${c} Compiler: ${e} ${b} Build type: ${e}${CMAKE_BUILD_TYPE} @@ -821,7 +823,16 @@ ${b} C compiler: ${e}${CMAKE_C_COMPILER} ${b} C++ compiler: ${e}${CMAKE_CXX_COMPILER} ${b} CFLAGS: ${e}${CMAKE_C_FLAGS_${_build_type}} ${CMAKE_C_FLAGS} ${b} CXXFLAGS: ${e}${CMAKE_CXX_FLAGS_${_build_type}} ${CMAKE_CXX_FLAGS} -${b} WARNCFLAGS: ${e}${WARNCFLAGS} +${b} WARNCFLAGS: ${e}${WARNCFLAGS}") +if(VCPKG_TOOLCHAIN) +message("\ +${c} Using vcpkg: ${e} +${b} Target Triplet: ${e}${VCPKG_TARGET_TRIPLET} +${b} Target Arch: ${e}${VCPKG_TARGET_ARCHITECTURE} +${b} Get runtime DLLs: ${e}${VCPKG_APPLOCAL_DEPS} +${b} Package root path: ${e}${VCPKG_CMAKE_FIND_ROOT_PATH}") +endif() +message("\ ${c} Build Options: ${e} ${b} Build apps: ${e}${ENABLE_APP} ${b} Shared library: ${e}${ENABLE_SHARED_LIB} @@ -829,7 +840,7 @@ ${b} Static library: ${e}${ENABLE_STATIC_LIB} ${b} Enable UnRAR: ${e}${ENABLE_UNRAR} ${b} Examples: ${e}${ENABLE_EXAMPLES} ${b} Tests: ${e}${ENABLE_TESTS} -${b} Build man pages: ${e}${ENABLE_DOCS} +${b} Build man pages: ${e}${ENABLE_MAN_PAGES} ${b} Build doxygen HTML: ${e}${ENABLE_DOXYGEN}") if(NOT WIN32) message("\ diff --git a/CMakeOptions.cmake b/CMakeOptions.cmake index 54bca51fee..96b4a430d8 100644 --- a/CMakeOptions.cmake +++ b/CMakeOptions.cmake @@ -1,6 +1,6 @@ # Features that can be enabled for cmake (see CMakeLists.txt) -if (WIN32) +if(WIN32) set(APP_CONFIG_DIRECTORY "." CACHE STRING "App Config directory.") @@ -77,9 +77,9 @@ option(ENABLE_CLAMONACC "Build clamonacc (Linux-only, requires ENABLE_APP))." ${ENABLE_CLAMONACC_DEFAULT}) -option(ENABLE_DOCS - "Generate documentation." - ${ENABLE_DOCS_DEFAULT}) +option(ENABLE_MAN_PAGES + "Generate man pages." + ${ENABLE_MAN_PAGES_DEFAULT}) option(ENABLE_DOXYGEN "Generate doxygen HTML documentation for clamav.h, libfreshclam.h." diff --git a/INSTALL.cmake.md b/INSTALL.cmake.md index 781cfde656..e54b895891 100644 --- a/INSTALL.cmake.md +++ b/INSTALL.cmake.md @@ -1,16 +1,11 @@ # Installation Instructions -**CAUTION**: ClamAV CMake support is experimental in this release and is not -recommended for production systems!!! - -Please help us stabilize it so we can deprecate autotools and Visual Studio. +CMake the preferred build system going forwards. The Windows Visual Studio +solution has been removed, and the Autotools build system will likely be +removed in the near future. _Known Issues / To-do:_ -- Support for building unit tests / feature tests and running with CTest - - A portion of this task will involve converting the shell scripts portions - to Python unit tests. -- Build fuzz targets. - LLVM bytecode runtime support. - Presently only the bytecode intepreter is supported. LLVM is preferable because it is faster. This task also requires updating to use a modern @@ -20,8 +15,12 @@ _Known Issues / To-do:_ is updated. - Complete the MAINTAINER_MODE option to generate jsparse files with GPerf. +**Table Of Contents** + - [Installation Instructions](#installation-instructions) - [CMake Basics](#cmake-basics) + - [Build requirements](#build-requirements) + - [Optional build requirements (Maintainer-Mode)](#optional-build-requirements-maintainer-mode) - [Basic Release build & system install](#basic-release-build--system-install) - [Basic Debug build](#basic-debug-build) - [Build and install to a specific install location (prefix)](#build-and-install-to-a-specific-install-location-prefix) @@ -32,38 +31,45 @@ _Known Issues / To-do:_ - [Example Build Commands](#example-build-commands) - [Linux release build, install to system](#linux-release-build-install-to-system) - [macOS debug build, custom OpenSSL path, build examples, local install](#macos-debug-build-custom-openssl-path-build-examples-local-install) - - [Windows Build](#windows-build) + - [Windows builds](#windows-builds) + - [Windows build (with vcpkg)](#windows-build-with-vcpkg) + - [Windows build (with Mussels)](#windows-build-with-mussels) + - [Build the Installer](#build-the-installer) - [External Depedencies](#external-depedencies) - [libclamav dependencies](#libclamav-dependencies) - [libfreshclam dependencies](#libfreshclam-dependencies) - [Application dependencies](#application-dependencies) - [Dependency build options](#dependency-build-options) - - [libcheck](#libcheck) - - [bzip2](#bzip2) - - [zlib](#zlib) - - [libxml2](#libxml2) - - [libpcre2](#libpcre2) - - [openssl (libcrypto, libssl)](#openssl-libcrypto-libssl) - - [libjson-c](#libjson-c) - - [libmspack](#libmspack) - - [iconv (POSIX-only)](#iconv-posix-only) - - [pthreads-win32 (Windows-only)](#pthreads-win32-windows-only) - - [llvm (optional, _see "Bytecode Runtime" section_)](#llvm-optional-see-bytecode-runtime-section) - - [libcurl](#libcurl) - - [ncurses or pdcurses, for clamdtop](#ncurses-or-pdcurses-for-clamdtop) + - [`libcheck`](#libcheck) + - [`bzip2`](#bzip2) + - [`zlib`](#zlib) + - [`libxml2`](#libxml2) + - [`libpcre2`](#libpcre2) + - [`openssl` (`libcrypto`, `libssl`)](#openssl-libcrypto-libssl) + - [`libjson-c`](#libjson-c) + - [`libmspack`](#libmspack) + - [`iconv` (POSIX-only)](#iconv-posix-only) + - [`pthreads-win32` (Windows-only)](#pthreads-win32-windows-only) + - [`llvm` (optional, _see "Bytecode Runtime" section_)](#llvm-optional-see-bytecode-runtime-section) + - [`libcurl`](#libcurl) + - [`ncurses` or `pdcurses`, for `clamdtop`](#ncurses-or-pdcurses-for-clamdtop) - [Bytecode Runtime](#bytecode-runtime) - [Compilers and Options](#compilers-and-options) - [Compiling For Multiple Architectures](#compiling-for-multiple-architectures) ## CMake Basics -Build requirements: +### Build requirements + +- CMake 3.14+ +- A C compiler toolchain such as gcc, clang, or Microsoft Visual Studio. +- Python 3 (to run the test suite) -- CMake 3.13+ -- A C-toolchain such as gcc, clang, or Microsoft Visual Studio. -- Flex and Bison. On Windows, `choco install winflexbison`. +### Optional build requirements (Maintainer-Mode) -_Important_: The following instructions assume that you have created a `build` +- GPerf, Flex and Bison. On Windows, `choco install winflexbison`. + +**_Important_**: The following instructions assume that you have created a `build` subdirectory and that subsequent commands are performed from said directory, like so: @@ -74,7 +80,7 @@ mkdir build && cd build ### Basic Release build & system install ```sh -cmake .. -DCMAKE_BUILD_TYPE="Release" +cmake .. -D CMAKE_BUILD_TYPE="Release" cmake --build . --config Release sudo cmake --build . --config Release --target install ``` @@ -84,7 +90,7 @@ sudo cmake --build . --config Release --target install In CMake, "Debug" builds mean that symbols are compiled in. ```sh -cmake .. -DCMAKE_BUILD_TYPE="Debug" +cmake .. -D CMAKE_BUILD_TYPE="Debug" cmake --build . --config Debug ``` @@ -92,20 +98,31 @@ You will likely also wish to disable compiler/linker optimizations, which you can do like so, using our custom `OPTIMIZE` option: ```sh -cmake .. -DCMAKE_BUILD_TYPE="Debug" -DOPTIMIZE=OFF +cmake .. -D CMAKE_BUILD_TYPE="Debug" -D OPTIMIZE=OFF cmake --build . --config Debug ``` -_Tip_: CMake provides four `CMAKE_BUILD_TYPE`s / options for `--config`): -- Debug -- Release -- MinSizeRel -- RelWithDebInfo +_Tip_: CMake provides four build configurations which you can set using the +`CMAKE_BUILD_TYPE` variable or the `--config` (`-C`) command line option. +These are: +- `Debug` +- `Release` +- `MinSizeRel` +- `RelWithDebInfo` + +For multi-config generators, such as "Visual Studio" and "Ninja Multi-Config", +you should not specify the config when you initially configure the project but +you _will_ need to specify the config when you build the project and when +running `ctest` or `cpack`. + +For single-config generators, such as "Make" or "Ninja", you will need to +specify the config when you configure the project, and should _not_ specify the +config when you build the project or run `ctest`. ### Build and install to a specific install location (prefix) ```sh -cmake -DCMAKE_INSTALL_PREFIX:PATH=install .. +cmake -D CMAKE_INSTALL_PREFIX:PATH=install .. cmake --build . --target install --config Release ``` @@ -121,13 +138,14 @@ cmake --build . --config Release ### Build and run tests The option to build and run tests is enabled by default, which requires that -you provide libcheck `check`, `check-devel`, `check-dev`, etc. +you provide libcheck (i.e. `check`, `check-devel`, `check-dev`, etc). If you're building with `ENABLE_LIBCLAMAV_ONLY=ON` or `ENABLE_APP=OFF`, then libcheck will still be required and you can still run the tests, but it will skip all app tests and only run the libclamav unit tests. -If you wish to disable test support, then configure with `-DENABLE_TESTS=OFF`. +If you wish to disable test support, then configure with `-D ENABLE_TESTS=OFF`. + - `-V`: Verbose @@ -145,7 +163,7 @@ ctest -C Release -V The following CMake options can be selected by using `-D`. For example: ```sh -cmake .. -DENABLE_EXAMPLES +cmake .. -D ENABLE_EXAMPLES cmake --build . --config Debug ``` @@ -201,7 +219,7 @@ cmake --build . --config Debug and requires the following environment variables to be set: - CC = `which clang` - CXX = `which clang++` - - SANITIZER = address _or_ undefined _or_ memory + - SANITIZER = "address" _or_ "undefined" _or_ "memory" _Default: `OFF`_ @@ -233,13 +251,13 @@ cmake --build . --config Debug - `ENABLE_MILTER`: (Posix-only) Build the clamav-milter mail filter daemon. Requires: `ENABLE_APP` - _Default: `OFF`_ + _Default: `OFF` for Mac & Windows, `ON` for Linux/Unix_ - `ENABLE_UNRAR`: Build & install libclamunrar (UnRAR) and libclamunrar_iface. _Default: `ON`_ -- `ENABLE_DOCS`: Generate man pages. +- `ENABLE_MAN_PAGES`: Generate man pages. _Default: `OFF`_ @@ -291,145 +309,226 @@ cmake --build . --config Debug #### Linux release build, install to system -This example sets the build system to Ninja instead of using Make, for speed. +This example sets the build generator to Ninja instead of using Make, for speed. You may need to first use `apt`/`dnf`/`pkg` to install `ninja-build` ```sh cmake .. -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ - -DENABLE_JSON_SHARED=OFF + -D CMAKE_BUILD_TYPE=Release \ + -D ENABLE_JSON_SHARED=OFF ninja sudo ninja install ``` #### macOS debug build, custom OpenSSL path, build examples, local install -macOS builds use Homebrew to install `flex`, `bison`, and each of the library -dependencies. +For macOS builds, we recommend using Homebrew to install the build tools, such +as `cmake`, `flex`, `bison`, as well as ClamAV's library dependencies. Note that explicit paths for OpenSSL are requires so as to avoid using an older OpenSSL install provided by the operating system. This example also: - -- Build system to Ninja instead of using Make. +- Sets the build generator to Ninja instead of using Make. - You may need to first use `brew` to install `ninja`. -- Sets build type to "Debug" and explicitly disables compiler optimizations. +- Sets build config to "Debug" and explicitly disables compiler optimizations. - Builds static libraries (and also shared libraries, which are on by default). - Builds the example programs, just to test them out. -- Sets the install path (prefix) to ./install +- Sets the install path (prefix) to `./install`. ```sh -cmake .. -G Ninja \ - -DCMAKE_BUILD_TYPE=Debug \ - -DOPTIMIZE=OFF \ - -DENABLE_JSON_SHARED=OFF \ - -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl@1.1/ \ - -DOPENSSL_CRYPTO_LIBRARY=/usr/local/opt/openssl@1.1/lib/libcrypto.1.1.dylib \ - -DOPENSSL_SSL_LIBRARY=/usr/local/opt/openssl@1.1/lib/libssl.1.1.dylib \ - -DENABLE_STATIC_LIB=ON \ - -DENABLE_EXAMPLES=ON \ - -DCMAKE_INSTALL_PREFIX=install +cmake .. -G Ninja \ + -D CMAKE_BUILD_TYPE=Debug \ + -D OPTIMIZE=OFF \ + -D ENABLE_JSON_SHARED=OFF \ + -D OPENSSL_ROOT_DIR=/usr/local/opt/openssl@1.1/ \ + -D OPENSSL_CRYPTO_LIBRARY=/usr/local/opt/openssl@1.1/lib/libcrypto.1.1.dylib \ + -D OPENSSL_SSL_LIBRARY=/usr/local/opt/openssl@1.1/lib/libssl.1.1.dylib \ + -D ENABLE_STATIC_LIB=ON \ + -D ENABLE_EXAMPLES=ON \ + -D CMAKE_INSTALL_PREFIX=install ninja ninja install ``` +#### Windows builds + +At a minimum you will need Visual Studio 2015 or newer, and CMake. +If you want to build the installer, you'll also need WiX Toolset. + +If you're using Chocolatey, you can install CMake and WiX simply like this: + +```ps1 +choco install cmake wixtoolset +``` + +Then open a new terminal so that CMake and WiX will be in your `$PATH`. + #### Windows build (with vcpkg) -Building with `vcpkg` is relatively easy, as all of the dependencies are built automatically. - -##### Preprequisites -You'll need CMake, git and vcpkg installed. - -- CMake: Download the installer [here](https://cmake.org/download/#latest) and - install it. -- Git: Download the installer [here](https://git-scm.com/download/win) and - install it. -- vcpkg: Get and install [vcpkg](https://github.com/microsoft/vcpkg). Set up - `vcpkg` as described in their README. Set the variable `$VCPKG_PATH` to the - location where you installed `vcpkg`. If you want to build for a 64 bit - system, don't forget to set `vcpkg`'s triple correctly: - ```ps1 - $env:VCPKG_DEFAULT_TRIPLET="x64-windows" - $VCPKG_PATH="..." # Path to your vcpkg installation - ``` - -##### Configuring and compiling -Next, install the required packages: +`vcpkg` can be used to build the ClamAV library dependencies automatically. + +`vcpkg` integrates really well with CMake, enabling CMake to find your compiled +libraries automatically, so you don't have to specify the include & library +paths manually as you do when using Mussels (below). + +**Preprequisites:** + +You'll need to install [vcpkg](https://github.com/microsoft/vcpkg). +See the `vcpkg` README for installation instructions. + +Once installed, set the variable `$VCPKG_PATH` to the location where you +installed `vcpkg`: + +```ps1 +$VCPKG_PATH="..." # Path to your vcpkg installation +``` + +By default, CMake and `vcpkg` build for 32-bit. If you want to build for 64-bit, +set the `VCPKG_DEFAULT_TRIPLET` environment variable: + +```ps1 +$env:VCPKG_DEFAULT_TRIPLET="x64-windows" +``` + +**Building the libraries and ClamAV:** + +Next, use `vcpkg` to build the required library dependencies: + ```ps1 & "$VCPKG_PATH\vcpkg" install 'curl[openssl]' 'json-c' 'libxml2' 'pcre2' 'pthreads' 'zlib' 'pdcurses' 'bzip2' ``` -Now check out the ClamAV repository and set your build environment up with -CMake: +Now configure the ClamAV build using the `CMAKE_TOOLCHAIN_FILE` variable which +will enable CMake to automatically find the libraries we built with `vcpkg`. + ```ps1 -git clone https://github.com/Cisco-Talos/clamav-devel -cd clamav-devel -mkdir build -cd build -cmake -A x64 ` - -DCMAKE_TOOLCHAIN_FILE="$VCPKG_PATH\scripts\buildsystems\vcpkg.cmake" ` - -DCMAKE_INSTALL_PREFIX='C:\clamav' .. -``` -You have to drop the `-A x64` arguments if you're building for 32 -bits, and correct the package paths accordingly. Also, if you want to install -via the MSVC project, set up the install path as you like. - -Finally, go ahead and build the project: +cmake .. -A x64 ` + -D CMAKE_TOOLCHAIN_FILE="$VCPKG_PATH\scripts\buildsystems\vcpkg.cmake" ` + -D CMAKE_INSTALL_PREFIX="install" +``` + +_Tip_: You have to drop the `-A x64` arguments if you're building for 32-bits, +and correct the package paths accordingly. + +Now, go ahead and build the project: + ```ps1 cmake --build . --config Release ``` -#### Windows Build (manual or with Mussels) +You can run the test suite with CTest: + +```ps1 +ctest -C Release +``` + +And you can install to the `install` directory (set above) like this: + +```ps1 +cmake --build . --config Release --target install +``` + +#### Windows build (with Mussels) + +Much like `vcpkg`, [Mussels](https://github.com/Cisco-Talos/Mussels) can be +used to automatically build the ClamAV library dependencies. Unlike `vcpkg`, +Mussels does not provide a mechanism for CMake to automatically detect the +library paths. + +**Preprequisites:** + +To build the library dependencies with Mussels, use Python's `pip` package +manager to install Mussels: + +```ps1 +python3 -m pip install mussels +``` + +Update the Mussels cookbooks to get the latest build recipes and set the +`clamav` cookbook to be trusted: + +```ps1 +msl update +msl cookbook trust clamav +``` + +Use `msl list` if you wish to see the recipes provided by the `clamav` cookbook. -Chocolatey (`choco`) is used to install `winflexbison` and `cmake`. -Visual Studio 2015+ is required, 2017+ recommended. +**Building the libraries and ClamAV:** -These instructions assume that `$env:CLAMAV_DEPENDENCIES` is set to your -[Mussels](https://github.com/Cisco-Talos/Mussels) `install\x64` directory and -that you've used Mussels to build the `clamav_deps` collection which will -provide the required libraries. +Build the `clamav_deps` recipe to compile ClamAV's library dependencies. +By default, Mussels will install them to `~\.mussels\install\` -_Tip_: Instead of building manually, try using Mussels to automate your build! +```ps1 +msl build clamav_deps +``` + +Next, set `$env:CLAMAV_DEPENDENCIES` to the location where Mussels built your +library dependencies: ```ps1 $env:CLAMAV_DEPENDENCIES="$env:userprofile\.mussels\install\x64" +``` + +To configure the project, run: + +```ps1 cmake .. -G "Visual Studio 15 2017" -A x64 ` - -DJSONC_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include\json-c" ` - -DJSONC_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\json-c.lib" ` - -DENABLE_JSON_SHARED=OFF ` - -DBZIP2_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` - -DBZIP2_LIBRARY_RELEASE="$env:CLAMAV_DEPENDENCIES\lib\libbz2.lib" ` - -DCURL_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` - -DCURL_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\libcurl_imp.lib" ` - -DOPENSSL_ROOT_DIR="$env:CLAMAV_DEPENDENCIES" ` - -DOPENSSL_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` - -DOPENSSL_CRYPTO_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\libcrypto.lib" ` - -DOPENSSL_SSL_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\libssl.lib" ` - -DZLIB_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\libssl.lib" ` - -DLIBXML2_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` - -DLIBXML2_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\libxml2.lib" ` - -DPCRE2_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` - -DPCRE2_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\pcre2-8.lib" ` - -DCURSES_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` - -DCURSES_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\pdcurses.lib" ` - -DPThreadW32_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` - -DPThreadW32_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\pthreadVC2.lib" ` - -DZLIB_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` - -DZLIB_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\zlibstatic.lib" ` - -DLIBCHECK_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` - -DLIBCHECK_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\checkDynamic.lib" ` - -DCMAKE_INSTALL_PREFIX="install" -cmake --build . --config Release --target install -copy $env:CLAMAV_DEPENDENCIES\lib\* .\install + -D JSONC_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include\json-c" ` + -D JSONC_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\json-c.lib" ` + -D ENABLE_JSON_SHARED=OFF ` + -D BZIP2_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` + -D BZIP2_LIBRARY_RELEASE="$env:CLAMAV_DEPENDENCIES\lib\libbz2.lib" ` + -D CURL_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` + -D CURL_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\libcurl_imp.lib" ` + -D OPENSSL_ROOT_DIR="$env:CLAMAV_DEPENDENCIES" ` + -D OPENSSL_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` + -D OPENSSL_CRYPTO_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\libcrypto.lib" ` + -D OPENSSL_SSL_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\libssl.lib" ` + -D ZLIB_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\libssl.lib" ` + -D LIBXML2_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` + -D LIBXML2_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\libxml2.lib" ` + -D PCRE2_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` + -D PCRE2_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\pcre2-8.lib" ` + -D CURSES_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` + -D CURSES_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\pdcurses.lib" ` + -D PThreadW32_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` + -D PThreadW32_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\pthreadVC2.lib" ` + -D ZLIB_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` + -D ZLIB_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\zlibstatic.lib" ` + -D LIBCHECK_INCLUDE_DIR="$env:CLAMAV_DEPENDENCIES\include" ` + -D LIBCHECK_LIBRARY="$env:CLAMAV_DEPENDENCIES\lib\checkDynamic.lib" ` + -D CMAKE_INSTALL_PREFIX="install" +``` + +Now, go ahead and build the project: + +```ps1 +cmake --build . --config Release +``` + +_Tip_: If you're having include-path issues when building, try building with +detailed verbosity so you can verify that the paths are correct: + +```ps1 +cmake --build . --config Release -- /verbosity:detailed ``` -_Tip_: If you're having include-path issues, try building with detailed verbosity: +You can run the test suite with CTest: ```ps1 -cmake --build . --config Release --target install -- /verbosity:detailed +ctest -C Release ``` +And you can install to the `install` (set above) like this: + +```ps1 +cmake --build . --config Release --target install +``` + +#### Build the Installer + To build the installer, you must have WIX Toolset installed. If you're using Chocolatey, you can install it simply with `choco install wixtoolset` and then open a new terminal so that WIX will be in your PATH. @@ -447,150 +546,146 @@ which include C headers. For macOS, Homebrew doesn't separate the headers. #### libclamav dependencies -App developers that only need libclamav can use the `-DENABLE_LIBCLAMAV_ONLY` +App developers that only need libclamav can use the `-D ENABLE_LIBCLAMAV_ONLY` option to bypass ClamAV app dependencies. libclamav requires these library dependencies: -- bzip2 -- zlib -- libxml2 -- libpcre2 -- openssl -- libjson-c -- iconv (POSIX-only, may be provided by system) -- pthreads (or on Windows: pthreads-win32) -- llvm (optional, _see [Bytecode Runtime](#bytecode-runtime)) +- `bzip2` +- `zlib` +- `libxml2` +- `libpcre2` +- `openssl` +- `json-c` +- `iconv` (POSIX-only, may be provided by system) +- `pthreads` (Provided by the system on POSIX; Use `pthreads-win32` on Windows) +- `llvm` (optional, _see [Bytecode Runtime](#bytecode-runtime)) #### libfreshclam dependencies If you want libclamav _and_ libfreshclam for your app, then use the -`-DENABLE_APP=OFF` option instead. +`-D ENABLE_APP=OFF` option instead. libfreshclam adds these additional library dependencies: -- libcurl +- `libcurl` #### Application dependencies For regular folk who want the ClamAV apps, you'll also need: -- ncurses (or pdcurses), for clamdtop. -- systemd, so clamd, freshclam, clamonacc may run as a systemd service (Linux). -- libsystemd, so clamd will support the clamd.ctl socket (Linux). +- `ncurses` (or `pdcurses`), for `clamdtop`. +- `systemd`, so `clamd`, `freshclam`, `clamonacc` may run as a `systemd` + service (Linux). +- `libsystemd`, so `clamd` will support the `clamd.ctl` socket (Linux). #### Dependency build options If you have custom install paths for the dependencies on your system or are on Windows, you may need to use the following options... -##### libcheck +##### `libcheck` ```sh - -DLIBCHECK_ROOT_DIR="_path to libcheck install root_" - -DLIBCHECK_INCLUDE_DIR="_filepath of libcheck header directory_" - -DLIBCHECK_LIBRARY="_filepath of libcheck library_" + -D LIBCHECK_ROOT_DIR="_path to libcheck install root_" + -D LIBCHECK_INCLUDE_DIR="_filepath of libcheck header directory_" + -D LIBCHECK_LIBRARY="_filepath of libcheck library_" ``` -##### bzip2 +##### `bzip2` ```sh - -DBZIP2_INCLUDE_DIR="_filepath of bzip2 header directory_" - -DBZIP2_LIBRARIES="_filepath of bzip2 library_" + -D BZIP2_INCLUDE_DIR="_filepath of bzip2 header directory_" + -D BZIP2_LIBRARIES="_filepath of bzip2 library_" ``` -##### zlib +##### `zlib` ```sh - -DZLIB_INCLUDE_DIR="_filepath of zlib header directory_" - -DZLIB_LIBRARY="_filepath of zlib library_" + -D ZLIB_INCLUDE_DIR="_filepath of zlib header directory_" + -D ZLIB_LIBRARY="_filepath of zlib library_" ``` -##### libxml2 +##### `libxml2` ```sh - -DLIBXML2_INCLUDE_DIR="_filepath of libxml2 header directory_" - -DLIBXML2_LIBRARY="_filepath of libxml2 library_" + -D LIBXML2_INCLUDE_DIR="_filepath of libxml2 header directory_" + -D LIBXML2_LIBRARY="_filepath of libxml2 library_" ``` -##### libpcre2 +##### `libpcre2` ```sh - -DPCRE2_INCLUDE_DIR="_filepath of libpcre2 header directory_" - -DPCRE2_LIBRARY="_filepath of libcpre2 library_" + -D PCRE2_INCLUDE_DIR="_filepath of libpcre2 header directory_" + -D PCRE2_LIBRARY="_filepath of libcpre2 library_" ``` -##### openssl (libcrypto, libssl) - -Hints to find openssl package: - -```sh - -DOPENSSL_ROOT_DIR="_path to openssl install root_" -``` +##### `openssl` (`libcrypto`, `libssl`) ```sh - -DOPENSSL_INCLUDE_DIR="_filepath of openssl header directory_" - -DOPENSSL_CRYPTO_LIBRARY="_filepath of libcrypto library_" - -DOPENSSL_SSL_LIBRARY="_filepath of libcrypto library_" + -D OPENSSL_ROOT_DIR="_path to openssl install root_" + -D OPENSSL_INCLUDE_DIR="_filepath of openssl header directory_" + -D OPENSSL_CRYPTO_LIBRARY="_filepath of libcrypto library_" + -D OPENSSL_SSL_LIBRARY="_filepath of libcrypto library_" ``` -##### libjson-c +##### `libjson-c` -Tip: You're strongly encouraged to link with the a static json-c library. +_Tip_: You're strongly encouraged to link with the a static json-c library. ```sh - -DJSONC_INCLUDE_DIR="_path to json-c header directory_" - -DJSONC_LIBRARY="_filepath of json-c library_" + -D JSONC_INCLUDE_DIR="_path to json-c header directory_" + -D JSONC_LIBRARY="_filepath of json-c library_" ``` -##### libmspack +##### `libmspack` -These options only apply if you use the `-DENABLE_EXTERNAL_MSPACK=ON` option. +These options only apply if you use the `-D ENABLE_EXTERNAL_MSPACK=ON` option. ```sh - -DMSPack_INCLUDE_DIR="_path to mspack header directory_" - -DMSPack_LIBRARY="_filepath of libmspack library_" + -D MSPack_INCLUDE_DIR="_path to mspack header directory_" + -D MSPack_LIBRARY="_filepath of libmspack library_" ``` -##### iconv (POSIX-only) +##### `iconv` (POSIX-only) On POSIX platforms, iconv might be part of the C library in which case you would not want to specify an external iconv library. ```sh - -DIconv_INCLUDE_DIR="_path to iconv header directory_" - -DIconv_LIBRARY="_filepath of iconv library_" + -D Iconv_INCLUDE_DIR="_path to iconv header directory_" + -D Iconv_LIBRARY="_filepath of iconv library_" ``` -##### pthreads-win32 (Windows-only) +##### `pthreads-win32` (Windows-only) On POSIX platforms, pthread support is detected automatically. On Windows, you need to specify the following: ```sh - -DPThreadW32_INCLUDE_DIR="_path to pthread-win32 header directory_" - -DPThreadW32_LIBRARY="_filepath of pthread-win32 library_" + -D PThreadW32_INCLUDE_DIR="_path to pthread-win32 header directory_" + -D PThreadW32_LIBRARY="_filepath of pthread-win32 library_" ``` -##### llvm (optional, _see "Bytecode Runtime" section_) +##### `llvm` (optional, _see "Bytecode Runtime" section_) ```sh - -DBYTECODE_RUNTIME="llvm" - -DLLVM_ROOT_DIR="_path to llvm install root_" -DLLVM_FIND_VERSION="3.6.0" + -D BYTECODE_RUNTIME="llvm" + -D LLVM_ROOT_DIR="_path to llvm install root_" -D LLVM_FIND_VERSION="3.6.0" ``` -##### libcurl +##### `libcurl` ```sh - -DCURL_INCLUDE_DIR="_path to curl header directory_" - -DCURL_LIBRARY="_filepath of curl library_" + -D CURL_INCLUDE_DIR="_path to curl header directory_" + -D CURL_LIBRARY="_filepath of curl library_" ``` -##### ncurses or pdcurses, for clamdtop +##### `ncurses` or `pdcurses`, for `clamdtop` ```sh - -DCURSES_INCLUDE_DIR="_path to curses header directory_" - -DCURSES_LIBRARY="_filepath of curses library_" + -D CURSES_INCLUDE_DIR="_path to curses header directory_" + -D CURSES_LIBRARY="_filepath of curses library_" ``` ##### Bytecode Runtime @@ -615,22 +710,22 @@ At the moment, the interpreter is the default runtime, while we work out compatibility issues with libLLVM. This default equates to: ```sh -cmake .. -DBYTECODE_RUNTIME="interpreter" +cmake .. -D BYTECODE_RUNTIME="interpreter" ``` To build using LLVM instead of the intereter, use: ```sh cmake .. \ - -DBYTECODE_RUNTIME="llvm" \ - -DLLVM_ROOT_DIR="/opt/llvm/3.6" \ - -DLLVM_FIND_VERSION="3.6.0" + -D BYTECODE_RUNTIME="llvm" \ + -D LLVM_ROOT_DIR="/opt/llvm/3.6" \ + -D LLVM_FIND_VERSION="3.6.0" ``` -To disable bytecode signature support entire, you may build with this option: +To disable bytecode signature support entirely, you may build with this option: ```sh -cmake .. -DBYTECODE_RUNTIME="none" +cmake .. -D BYTECODE_RUNTIME="none" ``` ## Compilers and Options diff --git a/README.md b/README.md index 82cc6329a4..1a042a5740 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,19 @@ # ClamAV -ClamAV® is an open source antivirus engine for detecting trojans, viruses, -malware & other malicious threats. +

+ Maeve, the ClamAV mascot +

+ +

+ ClamAV® is an open source antivirus engine for detecting trojans, viruses, + malware & other malicious threats. +

+ +

+ + + +

## Documentation & FAQ @@ -21,36 +33,25 @@ to get started! ## Installation Instructions -### UNIX - -#### Build from Source on Linux/Unix/Mac - -For basic compile and install instructions on Linux/Unix platforms, check out -the [install instructions](INSTALL.autotools.md). +#### Build from Source -For detailed instructions specific to building ClamAV please investigate -our the -[Linux/Unix/Mac Install instructions in the User Manual](https://www.clamav.net/documents/installing-clamav-on-unix-linux-macos-from-source). +For compile and install instructions with CMake, please see +[INSTALL.cmake.md](INSTALL.cmake.md). +For install instructions with the (now deprecated) autotools build system, see +[INSTALL.autotools.md](INSTALL.autotools.md). -For instructions on how to build ClamAV using our new *experimental* CMake -build tooling, see [INSTALL.cmake.md](INSTALL.cmake.md) +For additional instructions specific to building ClamAV please visit our +[online documentation](https://www.clamav.net/documents/clam-antivirus-user-manual). -#### Install from a binary package +#### Install from a binary package distribution For binary package distribution installation instructions, head over to [our website](https://www.clamav.net/documents/installing-clamav). -### Windows +#### Install using an installer (Windows) -#### Build from Source on Windows - -The instructions for building ClamAV from source on Windows is located in the -[Win32 README](win32/README.md). - -#### Using an Install Package - -We provide an installer to install ClamAV on Windows to "C:\\Program Files". -This install method will require you to have Adminstrator priveleges. +We provide installers to install ClamAV on Windows to "C:\\Program Files". +This install method will require you to have Administrator priveleges. We also provide a "Portable Install Package" (i.e. a zip of the required files) for users that may wish to run ClamAV without installing it to a system-owned @@ -59,9 +60,6 @@ directory. For details on how to use either option, head over to the [Windows Install instructions in the User Manual](https://www.clamav.net/documents/installing-clamav-on-windows). -For instructions on how to build ClamAV using our new *experimental* CMake -build tooling, see [INSTALL.cmake.md](INSTALL.cmake.md) - ### Upgrading from a previous version Some tips on [how to upgrade](https://www.clamav.net/documents/upgrading-clamav) @@ -78,8 +76,8 @@ Catch up on the latest about ClamAV by reading our ## Join the ClamAV Community The best way to get in touch with the ClamAV community is to join our -[our mailing lists](https://www.clamav.net/documents/mailing-lists-faq), and -tune to #clamav on [IRC](irc.freenode.net). +[mailing lists](https://www.clamav.net/documents/mailing-lists-faq) and tune to +#clamav on [IRC](irc.freenode.net) or [Discord](https://discord.gg/sGaxA5Q). ## Want to make a contribution? diff --git a/cmake/FindCURSES.cmake b/cmake/FindCURSES.cmake index 66e1b4f8dc..ebfd39fa54 100644 --- a/cmake/FindCURSES.cmake +++ b/cmake/FindCURSES.cmake @@ -130,11 +130,11 @@ else() set(CURSES_DEFINITIONS ${PC_PDCurses_CFLAGS_OTHER}) if (NOT TARGET Curses::curses) - add_library(Curses::curses INTERFACE IMPORTED) + add_library(Curses::curses UNKNOWN IMPORTED) set_target_properties(Curses::curses PROPERTIES INTERFACE_COMPILE_OPTIONS "${PC_PDCurses_CFLAGS_OTHER}" INTERFACE_INCLUDE_DIRECTORIES "${CURSES_INCLUDE_DIR}" - INTERFACE_LINK_LIBRARIES "${CURSES_LIBRARY}" + IMPORTED_LOCATION "${CURSES_LIBRARY}" ) endif() else() diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index f9b647ab63..507af6e6e2 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -1,79 +1,82 @@ +# Generate documentation (man pages, doxygen, etc.) -# -# man pages -# -# .1 files -configure_file(man/clamscan.1.in man/clamscan.1) -configure_file(man/freshclam.1.in man/freshclam.1) -configure_file(man/sigtool.1.in man/sigtool.1) -configure_file(man/clamdscan.1.in man/clamdscan.1) -configure_file(man/clamconf.1.in man/clamconf.1) -configure_file(man/clamdtop.1.in man/clamdtop.1) -configure_file(man/clamsubmit.1.in man/clamsubmit.1) -configure_file(man/clambc.1.in man/clambc.1) -# .5 files -configure_file(man/clamd.conf.5.in man/clamd.conf.5) -configure_file(man/clamav-milter.conf.5.in man/clamav-milter.conf.5) -configure_file(man/freshclam.conf.5.in man/freshclam.conf.5) -# .8 files -configure_file(man/clamd.8.in man/clamd.8) -configure_file(man/clamav-milter.8.in man/clamav-milter.8) -if(C_LINUX) - configure_file(man/clamonacc.8.in man/clamonacc.8) -endif() +if(ENABLE_MAN_PAGES) + # + # man pages + # + # .1 files + configure_file(man/clamscan.1.in man/clamscan.1) + configure_file(man/freshclam.1.in man/freshclam.1) + configure_file(man/sigtool.1.in man/sigtool.1) + configure_file(man/clamdscan.1.in man/clamdscan.1) + configure_file(man/clamconf.1.in man/clamconf.1) + configure_file(man/clamdtop.1.in man/clamdtop.1) + configure_file(man/clamsubmit.1.in man/clamsubmit.1) + configure_file(man/clambc.1.in man/clambc.1) + # .5 files + configure_file(man/clamd.conf.5.in man/clamd.conf.5) + configure_file(man/clamav-milter.conf.5.in man/clamav-milter.conf.5) + configure_file(man/freshclam.conf.5.in man/freshclam.conf.5) + # .8 files + configure_file(man/clamd.8.in man/clamd.8) + configure_file(man/clamav-milter.8.in man/clamav-milter.8) + if(C_LINUX) + configure_file(man/clamonacc.8.in man/clamonacc.8) + endif() -set(MAN1_FILES - man/clamscan.1 - man/freshclam.1 - man/sigtool.1 - man/clamdscan.1 - man/clamconf.1 - man/clamdtop.1 - man/clamsubmit.1 - man/clambc.1) -foreach(m IN LISTS MAN1_FILES) - install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/${m} - DESTINATION - ${CMAKE_INSTALL_PREFIX}/share/man/man1) -endforeach() + set(MAN1_FILES + man/clamscan.1 + man/freshclam.1 + man/sigtool.1 + man/clamdscan.1 + man/clamconf.1 + man/clamdtop.1 + man/clamsubmit.1 + man/clambc.1) + foreach(m IN LISTS MAN1_FILES) + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/${m} + DESTINATION + ${CMAKE_INSTALL_PREFIX}/share/man/man1) + endforeach() -set(MAN5_FILES - man/clamd.conf.5 - man/clamav-milter.conf.5 - man/freshclam.conf.5) -foreach(m IN LISTS MAN5_FILES) - install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/${m} - DESTINATION - ${CMAKE_INSTALL_PREFIX}/share/man/man5) -endforeach() + set(MAN5_FILES + man/clamd.conf.5 + man/clamav-milter.conf.5 + man/freshclam.conf.5) + foreach(m IN LISTS MAN5_FILES) + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/${m} + DESTINATION + ${CMAKE_INSTALL_PREFIX}/share/man/man5) + endforeach() -set(MAN8_FILES - man/clamd.8 - man/clamav-milter.8) -foreach(m IN LISTS MAN8_FILES) - install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/${m} - DESTINATION - ${CMAKE_INSTALL_PREFIX}/share/man/man8) -endforeach() + set(MAN8_FILES + man/clamd.8 + man/clamav-milter.8) + foreach(m IN LISTS MAN8_FILES) + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/${m} + DESTINATION + ${CMAKE_INSTALL_PREFIX}/share/man/man8) + endforeach() -if(C_LINUX) - # Also install Linux-only manpage - install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/man/clamonacc.8 - DESTINATION - ${CMAKE_INSTALL_PREFIX}/share/man/man8) + if(C_LINUX) + # Also install Linux-only manpage + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/man/clamonacc.8 + DESTINATION + ${CMAKE_INSTALL_PREFIX}/share/man/man8) + endif() endif() if(ENABLE_DOXYGEN) # - # clamav.h doxygen docs + # clamav.h and libfreshclam.h doxygen docs # find_package(Doxygen REQUIRED) @@ -91,8 +94,7 @@ if(ENABLE_DOXYGEN) doxygen_add_docs(doxygen ${CMAKE_SOURCE_DIR}/libclamav/clamav.h ${CMAKE_SOURCE_DIR}/libfreshclam/libfreshclam.h - COMMENT "Generate html documentation" - ) + COMMENT "Generate html documentation") install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION ${CMAKE_INSTALL_DOCDIR} diff --git a/logo.png b/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5a0db2d4ac217487fec92b1add7729269e1eee85 GIT binary patch literal 25476 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 PIewy{s;vT7vIzYjPI9lD literal 0 HcmV?d00001 diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt index dbccef2221..18d48f6244 100644 --- a/unit_tests/CMakeLists.txt +++ b/unit_tests/CMakeLists.txt @@ -182,10 +182,10 @@ if(WIN32) file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} BUILD) file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR} TMP) - file(TO_NATIVE_PATH $/check_clamav.exe CHECK_CLAMAV) + file(TO_NATIVE_PATH $ CHECK_CLAMAV) if(ENABLE_APP) - file(TO_NATIVE_PATH $/check_clamd.exe CHECK_CLAMD) - file(TO_NATIVE_PATH $/check_fpu_endian.exe CHECK_FPU_ENDIAN) + file(TO_NATIVE_PATH $ CHECK_CLAMD) + file(TO_NATIVE_PATH $ CHECK_FPU_ENDIAN) file(TO_NATIVE_PATH $/clambc.exe CLAMBC) file(TO_NATIVE_PATH $/clamd.exe CLAMD) @@ -198,7 +198,7 @@ if(WIN32) file(TO_NATIVE_PATH $/sigtool.exe SIGTOOL) endif() else() - set(LD_LIBRARY_PATH $:$:$:$:$:$:$ENV{LD_LIBRARY_PATH}) if(NOT ENABLE_LIBCLAMAV_ONLY) set(LD_LIBRARY_PATH $:${LD_LIBRARY_PATH}) endif() @@ -221,9 +221,12 @@ else() set(CLAMCONF $) set(FRESHCLAM $) set(SIGTOOL $) - - set(CLAMAV_MILTER $) - set(CLAMONACC $) + if(ENABLE_MILTER) + set(CLAMAV_MILTER $) + endif() + if(ENABLE_CLAMONACC) + set(CLAMONACC $) + endif() endif() endif() @@ -312,106 +315,136 @@ endif() if(WIN32) # # Prepare a test install, with all our DLL dependencies co-located with our EXEs and DLLs - # Generate GetLibs-$.ctest which will collect all required DLL and EXE dependencies when `ctest` is run. # - if(ENABLE_APP) - set(GEN_SCRIPT [[ - # Collect runtime DLL dependencies for our libs and apps - file(GET_RUNTIME_DEPENDENCIES - LIBRARIES - $ - $ - EXECUTABLES - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - RESOLVED_DEPENDENCIES_VAR _r_deps - UNRESOLVED_DEPENDENCIES_VAR _u_deps - DIRECTORIES - $ - $ - $ - $ - $ - $ - $ - $ - CONFLICTING_DEPENDENCIES_PREFIX CTEST_CONFLICTING_DEPENDENCIES + if(VCPKG_APPLOCAL_DEPS) + # + # Have CMake invoke itself to performa a local install for our test suite. + # + if(ENABLE_APP) + add_custom_target(test_install + ALL + "${CMAKE_COMMAND}" + -D CMAKE_INSTALL_PREFIX:string=$ + -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" + DEPENDS + check_clamav check_clamd check_fpu_endian + ClamAV::libclamav ClamAV::libfreshclam ClamAV::libunrar ClamAV::libunrar_iface ClamAV::libmspack + clambc clamd clamdscan clamdtop clamscan clamsubmit clamconf freshclam-bin sigtool ) - foreach(_file ${_r_deps}) - string(TOLOWER ${_file} _file_lower) - if(NOT ${_file_lower} MATCHES "c:[\\/]windows[\\/]system32.*") - message("Collecting DLL dependency: ${_file}") - file(COPY ${_file} DESTINATION $) - endif() - endforeach() + else() + add_custom_target(test_install + ALL + "${CMAKE_COMMAND}" + -D CMAKE_INSTALL_PREFIX:string=$ + -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" + DEPENDS + check_clamav + ClamAV::libclamav ClamAV::libfreshclam ClamAV::libunrar ClamAV::libunrar_iface ClamAV::libmspack + ) + endif() + else() + # + # Generate GetLibs-$.ctest which will collect all required DLL and EXE dependencies when `ctest` is run. + # + if(ENABLE_APP) + set(GEN_SCRIPT [[ + # Collect runtime DLL dependencies for our libs and apps + file(GET_RUNTIME_DEPENDENCIES + LIBRARIES + $ + $ + EXECUTABLES + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + RESOLVED_DEPENDENCIES_VAR _r_deps + UNRESOLVED_DEPENDENCIES_VAR _u_deps + DIRECTORIES + $ + $ + $ + $ + $ + $ + $ + $ + CONFLICTING_DEPENDENCIES_PREFIX CTEST_CONFLICTING_DEPENDENCIES + ) + foreach(_file ${_r_deps}) + string(TOLOWER ${_file} _file_lower) + if(NOT ${_file_lower} MATCHES "c:[\\/]windows[\\/]system32.*") + message("Collecting DLL dependency: ${_file}") + file(COPY ${_file} DESTINATION $) + endif() + endforeach() - # Collect our libs - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) + # Collect our libs + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) - # Collect our apps - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - ]]) - else() - # We don't have libfreshclam unit tests, so no need to check if ENABLE_LIBCLAMAV_ONLY is enabled. - set(GEN_SCRIPT [[ - # Collect runtime DLL dependencies for our libs - file(GET_RUNTIME_DEPENDENCIES - LIBRARIES - $ - EXECUTABLES - $ - RESOLVED_DEPENDENCIES_VAR _r_deps - UNRESOLVED_DEPENDENCIES_VAR _u_deps - DIRECTORIES - $ - $ - $ - $ - $ - $ - $ - CONFLICTING_DEPENDENCIES_PREFIX CTEST_CONFLICTING_DEPENDENCIES - ) - foreach(_file ${_r_deps}) - string(TOLOWER ${_file} _file_lower) - if(NOT ${_file_lower} MATCHES "c:[\\/]windows[\\/]system32.*") - message("DEPENDENCY: ${_file}") - file(COPY ${_file} DESTINATION $) - endif() - endforeach() + # Collect our apps + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + ]]) + else() + # We don't have libfreshclam unit tests, so no need to check if ENABLE_LIBCLAMAV_ONLY is enabled. + set(GEN_SCRIPT [[ + # Collect runtime DLL dependencies for our libs + file(GET_RUNTIME_DEPENDENCIES + LIBRARIES + $ + EXECUTABLES + $ + RESOLVED_DEPENDENCIES_VAR _r_deps + UNRESOLVED_DEPENDENCIES_VAR _u_deps + DIRECTORIES + $ + $ + $ + $ + $ + $ + $ + CONFLICTING_DEPENDENCIES_PREFIX CTEST_CONFLICTING_DEPENDENCIES + ) + foreach(_file ${_r_deps}) + string(TOLOWER ${_file} _file_lower) + if(NOT ${_file_lower} MATCHES "c:[\\/]windows[\\/]system32.*") + message("DEPENDENCY: ${_file}") + file(COPY ${_file} DESTINATION $) + endif() + endforeach() - # Collect our libs - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - file(COPY $ DESTINATION $) - ]]) - endif() + # Collect our libs + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + file(COPY $ DESTINATION $) + ]]) + endif() - file(GENERATE OUTPUT GetLibs-$.ctest CONTENT ${GEN_SCRIPT}) - set_directory_properties(PROPERTIES TEST_INCLUDE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Run-GetLibs.ctest) + file(GENERATE OUTPUT GetLibs-$.ctest CONTENT ${GEN_SCRIPT}) + set_directory_properties(PROPERTIES TEST_INCLUDE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Run-GetLibs.ctest) + endif() endif() \ No newline at end of file diff --git a/unit_tests/check_clamd.c b/unit_tests/check_clamd.c index 25d1e56d6e..2a562afce5 100644 --- a/unit_tests/check_clamd.c +++ b/unit_tests/check_clamd.c @@ -97,6 +97,11 @@ static void conn_setup_mayfail(int may) ck_assert_msg(sockd != -1, "Unable to create socket: %s\n", strerror(errno)); rc = connect(sockd, (struct sockaddr *)&nixsock, (socklen_t)sizeof(nixsock)); + if (rc == -1 && (may && (errno == ECONNREFUSED))) { + close(sockd); + sockd = -1; + return; + } ck_assert_msg(rc != -1, "Unable to connect(): %s\n", strerror(errno)); signal(SIGPIPE, SIG_IGN); @@ -683,7 +688,18 @@ START_TEST(test_connections) ck_assert_msg(getrlimit(RLIMIT_NOFILE, &rlim) != -1, "Failed to get RLIMIT_NOFILE: %s\n", strerror(errno)); num_fds = rlim.rlim_cur - 5; - sock = malloc(sizeof(int) * num_fds); +#ifdef C_DARWIN + /* While the limit when testing on macOS appears to be aroudn 1024, though + in testing on github actions macos-latest, get "connection refused" + after ~925 give or take. + It's possible the getrlimit API is incorrect post macOS Sierra, which + may explain the issue. In any case, limiting to 850 should be safe. + It's possible there' ssome other limitation at play on the GitHUb's + macos-latest shared environment. */ + num_fds = MIN(num_fds, 850); +#endif + + sock = malloc(sizeof(int) * num_fds); ck_assert_msg(!!sock, "malloc failed\n"); @@ -691,6 +707,11 @@ START_TEST(test_connections) /* just open connections, and let them time out */ conn_setup_mayfail(1); if (sockd == -1) { + /* close the previous one, to leave space for one more connection */ + i--; + close(sock[i]); + sock[i] = -1; + num_fds = i; break; } diff --git a/unit_tests/clamd_test.py b/unit_tests/clamd_test.py index cded6b5650..33e51a22fe 100644 --- a/unit_tests/clamd_test.py +++ b/unit_tests/clamd_test.py @@ -127,8 +127,14 @@ def tearDown(self): self.log.warning(f'Unexpected exception {exc}') pass # ignore self.proc = None - TC.clamd_pid.unlink(missing_ok=True) - TC.clamd_socket.unlink(missing_ok=True) + try: + TC.clamd_pid.unlink() + except Exception: + pass # missing_ok=True is too for common use. + try: + TC.clamd_socket.unlink() + except Exception: + pass # missing_ok=True is too for common use. self.verify_valgrind_log() @@ -378,6 +384,8 @@ def test_clamd_05_check_clamd(self): # Ok now run check_clamd to have fun with clamd's API output = self.execute_command(f'{TC.check_clamd}') + self.log.info(f'check_clamd stdout: \n{output.out}') + self.log.info(f'check_clamd stderr: \n{output.err}') assert output.ec == 0 # success expected_results = [ diff --git a/unit_tests/testcase.py b/unit_tests/testcase.py index ed291be159..76e242c6d4 100644 --- a/unit_tests/testcase.py +++ b/unit_tests/testcase.py @@ -162,7 +162,10 @@ def setUp(self): print("") log_path = Path(self.path_build / 'unit_tests' / f'{self._testMethodName}{self.log_suffix}') - log_path.unlink(missing_ok=True) + try: + log_path.unlink() + except Exception: + pass # missing_ok=True is too for common use. self.log = Logger(self._testMethodName, log_file=str(log_path)) def tearDown(self): @@ -607,6 +610,16 @@ def __run(self, cmd, cwd=None, env_vars={}, interact=""): sys_env = os.environ.copy() sys_env.update(env_vars) + if sys.platform == 'darwin': + # macOS doesn't propagate 'LD_LIBRARY_PATH' or 'DYLD_LIBRARY_PATH' + # to subprocesses, presumably as a security feature. + # We will likely need these for testing and can propagate them + # manually, like so: + if "LD_LIBRARY_PATH" in sys_env: + cmd = f"export LD_LIBRARY_PATH={sys_env['LD_LIBRARY_PATH']} && {cmd}" + if "DYLD_LIBRARY_PATH" in sys_env: + cmd = f"export DYLD_LIBRARY_PATH={sys_env['DYLD_LIBRARY_PATH']} && {cmd}" + self._logger.debug("Run command: %s" % (cmd,)) self._process = subprocess.Popen( cmd, diff --git a/win32/compat/strptime.c b/win32/compat/strptime.c index 883b8e215f..506482c7af 100644 --- a/win32/compat/strptime.c +++ b/win32/compat/strptime.c @@ -43,14 +43,6 @@ enum ptime_locale_status { not, raw }; #endif -struct tm *localtime_r(time_t const *t, struct tm *tp) -{ - struct tm *copy = localtime(t); - if (!copy) return NULL; - memcpy(tp, copy, sizeof(*tp)); - return tp; -} - typedef int bool; #define match_char(ch1, ch2) \ @@ -518,9 +510,10 @@ LOCALE_PARAM_DECL secs += *rp++ - '0'; } while (*rp >= '0' && *rp <= '9'); - if (localtime_r(&secs, tm) == NULL) + if (0 != localtime_s(tm, &secs)) { /* Error in function. */ return NULL; + } } break; case 'S': get_number(0, 61, 2);