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 0000000000..5a0db2d4ac Binary files /dev/null and b/logo.png differ 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);