cmake_minimum_required(VERSION 2.6) find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) # Support Unix Makefiles and Ninja set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") endif() project(BoxBackup) enable_testing() set(base_dir ${CMAKE_SOURCE_DIR}/../..) set(files_to_configure bin/bbackupd/bbackupd-config bin/bbstored/bbstored-certs bin/bbstored/bbstored-config contrib/mac_osx/org.boxbackup.bbackupd.plist contrib/mac_osx/org.boxbackup.bbstored.plist contrib/solaris/bbackupd-manifest.xml contrib/solaris/bbstored-manifest.xml contrib/debian/bbackupd contrib/debian/bbstored contrib/redhat/bbackupd contrib/redhat/bbstored contrib/suse/bbackupd contrib/suse/bbstored contrib/solaris/bbackupd-smf-method contrib/solaris/bbstored-smf-method contrib/windows/installer/boxbackup.mpi infrastructure/BoxPlatform.pm infrastructure/makebuildenv.pl infrastructure/makedistribution.pl lib/bbackupquery/makedocumentation.pl lib/common/BoxPortsAndFiles.h lib/common/makeexception.pl lib/raidfile/raidfile-config lib/server/makeprotocol.pl runtest.pl test/backupstorefix/testfiles/testbackupstorefix.pl test/bbackupd/testfiles/bbackupd.conf test/bbackupd/testfiles/bbackupd-exclude.conf test/bbackupd/testfiles/bbackupd-snapshot.conf test/bbackupd/testfiles/bbackupd-symlink.conf test/bbackupd/testfiles/bbackupd-temploc.conf test/bbackupd/testfiles/extcheck1.pl test/bbackupd/testfiles/extcheck2.pl test/bbackupd/testfiles/notifyscript.pl test/bbackupd/testfiles/syncallowscript.pl ) # We need to substitute TARGET_PERL in test/bbackupd/testfiles/bbackupd.conf, so define it # as a variable before running configure_file(). include(FindPerl) set(TARGET_PERL ${PERL_EXECUTABLE}) function(replace_file_if_different dest_file source_file) execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${source_file}" "${dest_file}") execute_process( COMMAND "${CMAKE_COMMAND}" -E remove "${source_file}") endfunction() function(move_file_if_exists source_file dest_file) if(EXISTS "${source_file}") execute_process( COMMAND "${CMAKE_COMMAND}" -E rename "${source_file}" "${dest_file}") endif() endfunction() foreach(file_to_configure ${files_to_configure}) configure_file("${base_dir}/${file_to_configure}.in" "${base_dir}/${file_to_configure}.out" @ONLY) replace_file_if_different( "${base_dir}/${file_to_configure}" "${base_dir}/${file_to_configure}.out") endforeach() # If BOXBACKUP_VERSION is defined when running CMake (as the AppVeyor config does), use it # as-is, since it contains the full version number, branch, and platform (Win32/Win64): if(BOXBACKUP_VERSION) set(boxbackup_version ${BOXBACKUP_VERSION}) # Remove CPACK_SYSTEM_NAME from the default CPACK_PACKAGE_NAME, because it's already # included in the CPACK_PACKAGE_VERSION: set(CPACK_PACKAGE_FILE_NAME ${CMAKE_PROJECT_NAME}-${boxbackup_version}) else() # Work out the current Box version (requires Perl) and update lib/common/BoxVersion.h, # but only if it has changed, to avoid unnecessary complete rebuilds due to timestamps. execute_process( COMMAND ${PERL_EXECUTABLE} ${base_dir}/infrastructure/cmake/getversion.pl WORKING_DIRECTORY ${base_dir}/infrastructure RESULT_VARIABLE status OUTPUT_VARIABLE boxbackup_version OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_VARIABLE command_output) if(NOT status EQUAL 0) message(FATAL_ERROR "Failed to execute: " "${PERL_EXECUTABLE} ${base_dir}/infrastructure/cmake/getversion.pl: " "status ${status}: ${command_output}") endif() endif() file(WRITE "${base_dir}/lib/common/BoxVersion.h.new" "#define BOX_VERSION \"${boxbackup_version}\"\n") replace_file_if_different( "${base_dir}/lib/common/BoxVersion.h" "${base_dir}/lib/common/BoxVersion.h.new") add_definitions(-DBOX_CMAKE -DNEED_BOX_VERSION_H) if(WIN32) add_definitions(-DWIN32) endif() # Parsing Makefile.extra files in CMake script is a pain, so the relevant rules for # code-generating Perl scripts are hard-coded here. set(exception_files lib/backupclient/ClientException.txt lib/backupstore/BackupStoreException.txt lib/common/CommonException.txt lib/common/ConversionException.txt lib/compress/CompressException.txt lib/crypto/CipherException.txt lib/httpserver/HTTPException.txt lib/raidfile/RaidFileException.txt lib/server/ServerException.txt lib/server/ConnectionException.txt ) foreach(exception_file ${exception_files}) string(REGEX MATCH "(.*)/(.*).txt" valid_exception_file ${exception_file}) if(NOT valid_exception_file) message(FATAL_ERROR "invalid exception file: '${exception_file}'") endif() set(output_file "${base_dir}/${CMAKE_MATCH_1}/autogen_${CMAKE_MATCH_2}.cpp") add_custom_command(OUTPUT "${output_file}" MAIN_DEPENDENCY "${base_dir}/${exception_file}" COMMAND ${PERL_EXECUTABLE} "${base_dir}/lib/common/makeexception.pl" "${CMAKE_MATCH_2}.txt" WORKING_DIRECTORY "${base_dir}/${CMAKE_MATCH_1}") string(REPLACE "/" "_" module_name ${CMAKE_MATCH_1}) set(${module_name}_extra_files ${${module_name}_extra_files} ${output_file}) endforeach() set(protocol_files lib/backupstore/BackupProtocol.txt test/basicserver/TestProtocol.txt ) foreach(protocol_file ${protocol_files}) string(REGEX MATCH "(.*)/(.*).txt" valid_protocol_file ${protocol_file}) if(NOT valid_protocol_file) message(FATAL_ERROR "invalid protocol file: '${protocol_file}'") endif() set(output_file "${base_dir}/${CMAKE_MATCH_1}/autogen_${CMAKE_MATCH_2}.cpp") add_custom_command(OUTPUT "${output_file}" MAIN_DEPENDENCY "${base_dir}/${protocol_file}" COMMAND ${PERL_EXECUTABLE} "${base_dir}/lib/server/makeprotocol.pl" "${CMAKE_MATCH_2}.txt" WORKING_DIRECTORY "${base_dir}/${CMAKE_MATCH_1}") string(REPLACE "/" "_" module_name ${CMAKE_MATCH_1}) set(${module_name}_extra_files ${${module_name}_extra_files} ${output_file}) endforeach() set(documentation_files lib/bbackupquery/Documentation.txt ) foreach(documentation_file ${documentation_files}) string(REGEX MATCH "(.*)/(.*).txt" valid_documentation_file ${documentation_file}) if(NOT valid_documentation_file) message(FATAL_ERROR "invalid documentation file: '${documentation_file}'") endif() set(output_file "${base_dir}/${CMAKE_MATCH_1}/autogen_${CMAKE_MATCH_2}.cpp") add_custom_command(OUTPUT "${output_file}" MAIN_DEPENDENCY "${base_dir}/${documentation_file}" COMMAND ${PERL_EXECUTABLE} "${base_dir}/lib/bbackupquery/makedocumentation.pl" WORKING_DIRECTORY "${base_dir}/${CMAKE_MATCH_1}") string(REPLACE "/" "_" module_name ${CMAKE_MATCH_1}) set(${module_name}_extra_files ${${module_name}_extra_files} ${output_file}) endforeach() set(testmain_template_cpp "${base_dir}/infrastructure/buildenv-testmain-template.cpp" ) set(release_or_debug_dir "${base_dir}/$<$:debug>$<$:release>$<$:release>" ) file(STRINGS ${base_dir}/modules.txt module_deps REGEX "^[^#]") foreach(module_dep ${module_deps}) string(REGEX MATCH "([^ ]+)[ ]*(.*)" valid_module_line ${module_dep}) if(valid_module_line) if(DEBUG) message(STATUS "found module: ${CMAKE_MATCH_1} -> ${CMAKE_MATCH_2}") endif() set(module_dir ${CMAKE_MATCH_1}) set(module_path ${base_dir}/${module_dir}) string(REPLACE "/" "_" module_name ${CMAKE_MATCH_1}) string(REPLACE "/" "_" dependencies "${CMAKE_MATCH_2}") # We are replacing QDBM's normal build system, and we only want to include # the modules that we actually need, to avoid warnings about duplicate # definitions, and potential conflicts with Box Backup code in future, so # we specify the C files to compile in explicitly. if(module_name STREQUAL "qdbm") file(GLOB module_files ${module_path}/depot.c ${module_path}/myconf.c) else() file(GLOB module_files ${module_path}/*.cpp ${module_path}/*.h) endif() set(module_files ${module_files} ${${module_name}_extra_files}) string(REGEX REPLACE "^ " "" dependencies "${dependencies}") string(REGEX REPLACE " $" "" dependencies "${dependencies}") if(module_name MATCHES "^bin_") string(REGEX MATCH "^bin_(.*)" valid_exe ${module_name}) set(bin_name ${CMAKE_MATCH_1}) if(DEBUG) message(STATUS "add executable '${module_name}': '${module_files}'") endif() add_executable(${module_name} ${module_files}) # Rename the output executable from bin_bbackupd(.exe) to bbackupd(.exe): set_target_properties(${module_name} PROPERTIES OUTPUT_NAME "${bin_name}") # Use a custom post-build command instead of install(...) to install # binaries ready for running tests, because we don't want "make install" to # do this too, and absolute-path installations break the CPack generators. add_custom_command(TARGET ${module_name} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "$" "${release_or_debug_dir}/${module_dir}/${bin_name}${CMAKE_EXECUTABLE_SUFFIX}" VERBATIM) # For "make install" and CPack generators: install(TARGETS ${module_name} RUNTIME CONFIGURATIONS Debug;Release DESTINATION "." COMPONENT Applications) elseif(module_name MATCHES "^test_") string(REGEX MATCH "^test_(.*)" valid_test ${module_name}) set(test_name ${CMAKE_MATCH_1}) set(bin_name ${module_name}) if(DEBUG) message(STATUS "add test '${module_name}': '${module_files}'") endif() set(module_files ${module_files} "${testmain_template_cpp}") add_executable(${module_name} ${module_files}) # Use a custom post-build command instead of install(...) to install # binaries ready for running tests, because we don't want "make install" to # do this too, and absolute-path installations break the CPack generators. add_custom_command(TARGET ${module_name} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "$" "${release_or_debug_dir}/${module_dir}/${bin_name}${CMAKE_EXECUTABLE_SUFFIX}" VERBATIM) if(${APPVEYOR_MODE}) set(appveyor_runtest_pl_switch -a) else() set(appveyor_runtest_pl_switch) endif() if(WIN32) set(test_command_internal "$") else() set(test_command_internal "./$") endif() target_compile_definitions(${module_name} PRIVATE -DTEST_EXECUTABLE="${test_command_internal}") add_test(NAME ${test_name} COMMAND ${PERL_EXECUTABLE} ${base_dir}/runtest.pl ${appveyor_runtest_pl_switch} -c ${test_name} $<$:DEBUG>$<$:RELEASE>$<$:RELEASE> "$" "${test_command_internal}" WORKING_DIRECTORY ${base_dir}) if(${APPVEYOR_MODE}) execute_process(COMMAND appveyor AddTest -Name ${test_name} -Framework Custom -FileName "") endif() # It helps with debugging if the test depends on another step which # prepares the target directory, and is always out of date. add_custom_target(${module_name}-prepare COMMAND ${PERL_EXECUTABLE} ${base_dir}/runtest.pl -n -c ${test_name} $<$:DEBUG>$<$:RELEASE>$<$:RELEASE> "$" "${test_command_internal}" WORKING_DIRECTORY ${base_dir}) elseif(module_name MATCHES "^(lib_.*|qdbm)$") if(DEBUG) message(STATUS "add library '${module_name}': '${module_files}'") endif() add_library(${module_name} STATIC ${module_files}) else() message(FATAL_ERROR "Unsupported module type: " ${module_name}) endif() target_compile_definitions(${module_name} PRIVATE -DBOX_MODULE="${module_name}") if(dependencies) string(REGEX REPLACE "[ ]+" ";" dependency_list "${dependencies}") foreach(dependency ${dependency_list}) if(DEBUG) message(STATUS "add dependency to '${module_name}': '${dependency}'") endif() add_dependencies(${module_name} ${dependency}) if(dependency MATCHES "^(lib_.*|qdbm)$") # message(STATUS "add link library to '${module_name}': '${dependency}'") target_link_libraries(${module_name} PUBLIC ${dependency}) endif() # We can't make a binary depend on another binary, so we need to # add the dependency's directory directly to our include path. if(dependency MATCHES "^bin_") get_property(dep_include_dirs TARGET ${dependency} PROPERTY INTERFACE_INCLUDE_DIRECTORIES) target_include_directories(${module_name} PUBLIC ${dep_include_dirs}) endif() endforeach() endif() target_include_directories(${module_name} PUBLIC ${module_path}) endif() endforeach() if(WIN32) install(FILES ${base_dir}/bin/bbackupd/win32/NotifySysAdmin.vbs DESTINATION "." COMPONENT Extras) install(FILES ${base_dir}/bin/bbackupd/win32/bbackupd.conf DESTINATION "." COMPONENT Extras) else() install(FILES ${base_dir}/bin/bbackupd/bbackupd-config DESTINATION "." COMPONENT Extras) endif() # We can't do anything conditional on CMAKE_BUILD_TYPE because that's not valid for multi-configuration # generators such as MSVC. We need to use a generator expression instead. target_compile_definitions(lib_common PUBLIC $<$:BOX_RELEASE_BUILD>) # Detect platform features and write BoxConfig.h.in. Reuse code from # infrastructure/m4/boxbackup_tests.m4 where possible include(CheckCXXCompilerFlag) include(CheckCXXSourceCompiles) include(CheckCXXSourceRuns) include(CheckFunctionExists) include(CheckIncludeFiles) include(CheckLibraryExists) include(CheckSymbolExists) set(boxconfig_h_file "${CMAKE_BINARY_DIR}/BoxConfig.h.in") file(REMOVE "${boxconfig_h_file}") file(WRITE "${boxconfig_h_file}" "// Auto-generated by CMake. Do not edit.\n") if(WIN32) target_link_libraries(lib_common PUBLIC ws2_32 gdi32) endif() # On Windows we want to statically link zlib to make debugging and distribution easier, # but FindZLIB.cmake doesn't offer that as an option, so we have to go through some # contortions to "find" the correct library. ZLIB_ROOT is required in this case. if(WIN32) if(NOT DEFINED ZLIB_ROOT) message(FATAL_ERROR "You must set ZLIB_ROOT to point to include/zlib.h and lib/zlibstatic[d].lib on Windows") endif() message(STATUS "Searching for Zlib in: ${ZLIB_ROOT}") find_path(ZLIB_INCLUDE_DIR zlib.h PATHS ${ZLIB_ROOT}/include NO_DEFAULT_PATH) include_directories(${ZLIB_INCLUDE_DIR}) message(STATUS "Found Zlib headers: ${ZLIB_INCLUDE_DIR}") # We must link against zlibstaticD if this is a debug build, otherwise # we have a C runtime mismatch (/MD versus /MDd) and the application # crashes at runtime. find_library(ZLIB_LIBRARY_STATIC_DEBUG NAMES zlibstaticd PATHS ${ZLIB_ROOT}/lib NO_DEFAULT_PATH) find_library(ZLIB_LIBRARY_STATIC_RELEASE NAMES zlibstatic PATHS ${ZLIB_ROOT}/lib NO_DEFAULT_PATH) target_link_libraries(lib_compress PUBLIC debug ${ZLIB_LIBRARY_STATIC_DEBUG} optimized ${ZLIB_LIBRARY_STATIC_RELEASE}) else() find_package(ZLIB REQUIRED) include_directories(${ZLIB_INCLUDE_DIRS}) target_link_libraries(lib_compress PUBLIC ${ZLIB_LIBRARIES}) endif() # Link to OpenSSL # Workaround for incorrect library suffixes searched by FindOpenSSL: # https://gitlab.kitware.com/cmake/cmake/issues/17604 if(WIN32 AND MSVC) find_package(OpenSSL) set(OPENSSL_SSL_LIBRARY ${SSL_EAY_RELEASE}) set(OPENSSL_CRYPTO_LIBRARY ${LIB_EAY_RELEASE}) set(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY} crypt32) find_package_handle_standard_args(OpenSSL REQUIRED_VARS OPENSSL_SSL_LIBRARY OPENSSL_CRYPTO_LIBRARY OPENSSL_INCLUDE_DIR VERSION_VAR OPENSSL_VERSION FAIL_MESSAGE "Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR" ) else() find_package(OpenSSL REQUIRED) endif() include_directories(${OPENSSL_INCLUDE_DIR}) target_link_libraries(lib_crypto PUBLIC ${OPENSSL_LIBRARIES}) # Link to PCRE if (WIN32) if(NOT DEFINED PCRE_ROOT) message(FATAL_ERROR "You must set PCRE_ROOT to point to include/pcreposix.h and lib/pcreposix[d].lib on Windows") endif() target_compile_definitions(lib_common PUBLIC -DPCRE_STATIC) find_library(pcreposix_lib_path pcreposix ${PCRE_ROOT}/lib) find_library(pcreposixd_lib_path pcreposixd ${PCRE_ROOT}/lib) find_library(pcre_lib_path pcre ${PCRE_ROOT}/lib) find_library(pcred_lib_path pcred ${PCRE_ROOT}/lib) target_link_libraries(lib_common PUBLIC debug "${pcreposixd_lib_path}" optimized "${pcreposix_lib_path}") target_link_libraries(lib_common PUBLIC debug "${pcred_lib_path}" optimized "${pcre_lib_path}") include_directories(${PCRE_ROOT}/include) else() find_package(PkgConfig REQUIRED) pkg_check_modules(PCRE REQUIRED libpcreposix) include_directories(${PCRE_INCLUDE_DIRS}) target_link_libraries(lib_common PUBLIC ${PCRE_LIBRARIES}) if(DEBUG) message(STATUS "Linking PCRE libraries from ${PCRE_LIBRARY_DIRS}: ${PCRE_LIBRARIES}") endif() endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}") find_package(Readline) if(READLINE_FOUND) include_directories(${Readline_INCLUDE_DIR}) target_link_libraries(lib_common PUBLIC ${Readline_LIBRARY}) endif() set(boxconfig_cmake_h_dir "${base_dir}/lib/common") # Get the values of all directories added to the INCLUDE_DIRECTORIES property # by include_directory() statements, and save it in CMAKE_REQUIRED_INCLUDES # which check_include_files() uses to set the include file search path: get_property(CMAKE_REQUIRED_INCLUDES DIRECTORY PROPERTY INCLUDE_DIRECTORIES) list(APPEND CMAKE_REQUIRED_INCLUDES "${boxconfig_cmake_h_dir}") # message(STATUS "CMAKE_REQUIRED_INCLUDES=${CMAKE_REQUIRED_INCLUDES}") # Save the original BoxConfig.cmake.h so that we can move it back later, # and not need to recompile everything. move_file_if_exists( "${boxconfig_cmake_h_dir}/BoxConfig.cmake.h" "${boxconfig_cmake_h_dir}/BoxConfig.cmake.h.bak") foreach(m4_filename boxbackup_tests.m4 ax_check_mount_point.m4 ax_func_syscall.m4) file(STRINGS "${base_dir}/infrastructure/m4/${m4_filename}" m4_functions REGEX "^ *(AC|AX|BOX)_[A-Z_]+\\(.*\\)$") foreach(m4_function ${m4_functions}) if(DEBUG) message(STATUS "Processing m4_function: ${m4_function}") endif() string(REGEX MATCH .* ac_check_headers ${m4_function}) if(m4_function MATCHES "^ *AC_CHECK_HEADERS?\\(\\[([a-z./ ]+)\\](.*)\\)$") if(DEBUG) message(STATUS "Processing ac_check_headers: ${CMAKE_MATCH_1}") endif() # http://stackoverflow.com/questions/5272781/what-is-common-way-to-split-string-into-list-with-cmake string(REPLACE " " ";" header_files ${CMAKE_MATCH_1}) foreach(header_file ${header_files}) list(APPEND detect_header_files ${header_file}) endforeach() elseif(m4_function MATCHES "^ *AC_CHECK_FUNCS\\(\\[([a-z./_ ]+)\\](.*)\\)$") if(DEBUG) message(STATUS "Processing ac_check_funcs: ${CMAKE_MATCH_1}") endif() # http://stackoverflow.com/questions/5272781/what-is-common-way-to-split-string-into-list-with-cmake string(REPLACE " " ";" function_names ${CMAKE_MATCH_1}) foreach(function_name ${function_names}) list(APPEND detect_functions ${function_name}) endforeach() elseif(m4_function MATCHES "^ *AC_CHECK_DECLS\\(\\[([A-Za-z._/ ]+)\\](,,, ..#include <([^>]+)>..)?\\)$") if(DEBUG) message(STATUS "Processing ac_check_decls: ${CMAKE_MATCH_1} in ${CMAKE_MATCH_3}") endif() # http://stackoverflow.com/questions/5272781/what-is-common-way-to-split-string-into-list-with-cmake string(REPLACE " " ";" decl_names "${CMAKE_MATCH_1}") string(REPLACE " " ";" header_files "${CMAKE_MATCH_3}") foreach(decl_name ${decl_names}) string(TOUPPER ${decl_name} platform_var_name) string(REGEX REPLACE "[/.]" "_" platform_var_name ${platform_var_name}) check_symbol_exists("${decl_name}" "${header_files}" HAVE_DECL_${platform_var_name}) file(APPEND "${boxconfig_h_file}" "#cmakedefine01 HAVE_DECL_${platform_var_name}\n") endforeach() elseif(m4_function MATCHES "^ *AC_SEARCH_LIBS\\(\\[([A-Za-z._/ ]+)\\], \\[([A-Za-z._]+)\\]\\)$") if(DEBUG) message(STATUS "Processing ac_search_libs: ${CMAKE_MATCH_1} in ${CMAKE_MATCH_2}") endif() set(function_name ${CMAKE_MATCH_1}) # http://stackoverflow.com/questions/5272781/what-is-common-way-to-split-string-into-list-with-cmake string(REPLACE " " ";" library_names "${CMAKE_MATCH_2}") foreach(library_name ${library_names}) string(TOUPPER ${library_name} platform_var_name) check_library_exists(${library_name} ${function_name} "" HAVE_LIB_${platform_var_name}) if(HAVE_LIB_${platform_var_name}) target_link_libraries(lib_common PUBLIC ${library_name}) endif() endforeach() elseif(m4_function MATCHES "^ *AC_CHECK_MEMBERS\\(\\[([A-Za-z._/ ]+)\\.([[A-Za-z_]+)\\](,,, ..(#include <([^>]+)>)..)?\\)$") if(DEBUG) message(STATUS "Processing ac_check_members: ${CMAKE_MATCH_1}.${CMAKE_MATCH_2} in ${CMAKE_MATCH_5}") endif() set(struct_name "${CMAKE_MATCH_1}") set(member_name "${CMAKE_MATCH_2}") set(include_file "${CMAKE_MATCH_5}") string(TOUPPER "${struct_name}_${member_name}" platform_var_name) string(REGEX REPLACE "[/. ]" "_" platform_var_name ${platform_var_name}) CHECK_CXX_SOURCE_COMPILES([=[ #include "BoxConfig.cmake.h" #include <${include_file}> int main() { ${struct_name} foo; return sizeof(foo.${member_name}) > 0 ? 0 : 1; } ]=] "HAVE_${platform_var_name}") file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE_${platform_var_name}\n") elseif(m4_function MATCHES "^ *BOX_CHECK_CXX_FLAG\\((-[A-Za-z_,=-]+)\\)") if(DEBUG) message(STATUS "Processing BOX_CHECK_CXX_FLAG: ${CMAKE_MATCH_1}") endif() if(NOT CMAKE_MATCH_1 STREQUAL "-Wall") set(flag "${CMAKE_MATCH_1}") string(TOLOWER "have_flag_${flag}" have_flag_var_name) string(REGEX REPLACE "[^a-z_]" "_" have_flag_var_name ${have_flag_var_name}) string(REGEX REPLACE "__+" "_" have_flag_var_name ${have_flag_var_name}) CHECK_CXX_COMPILER_FLAG(${flag} ${have_flag_var_name}) if(${have_flag_var_name}) add_definitions("${flag}") endif() endif() endif() endforeach() # Build an intermediate version of BoxConfig.cmake.h for use in the following tests. configure_file("${boxconfig_h_file}" "${boxconfig_cmake_h_dir}/BoxConfig.cmake.h") endforeach() list(APPEND detect_header_files mntent.h sys/mnttab.h sys/mount.h sys/param.h) foreach(header_file ${detect_header_files}) list(APPEND detect_header_files ${header_file}) string(TOUPPER ${header_file} platform_var_name) string(REGEX REPLACE "[/.]" "_" platform_var_name ${platform_var_name}) check_include_files(${header_file} HAVE_${platform_var_name}) file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE_${platform_var_name}\n") endforeach() if(NOT HAVE_PCREPOSIX_H) message(FATAL_ERROR "pcreposix.h not found at PCRE_ROOT/include: ${PCRE_ROOT}/include") endif() # PCRE is required, so unconditionally define this: set(HAVE_REGEX_SUPPORT 1) file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE_REGEX_SUPPORT\n") foreach(function_name ${detect_functions}) string(TOUPPER ${function_name} platform_var_name) string(REGEX REPLACE "[/.]" "_" platform_var_name ${platform_var_name}) check_function_exists(${function_name} HAVE_${platform_var_name}) file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE_${platform_var_name}\n") endforeach() check_symbol_exists(dirfd "dirent.h" HAVE_DECL_DIRFD) file(APPEND "${boxconfig_h_file}" "#cmakedefine01 HAVE_DECL_DIRFD\n") # Emulate ax_check_mount_point.m4 # These checks are run by multi-line M4 commands which are harder to parse/fake using # regexps above, so we hard-code them here: CHECK_CXX_SOURCE_COMPILES([=[ #include "BoxConfig.cmake.h" #ifdef HAVE_SYS_PARAM_H # include #endif #include int main() { struct statfs foo; return sizeof(foo.f_mntonname) > 0 ? 0 : 1; } ]=] "HAVE_STRUCT_STATFS_F_MNTONNAME") file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE_STRUCT_STATFS_F_MNTONNAME\n") CHECK_CXX_SOURCE_COMPILES([=[ #include "BoxConfig.cmake.h" #ifdef HAVE_SYS_PARAM_H # include #endif #include int main() { struct statvfs foo; return sizeof(foo.f_mntonname) > 0 ? 0 : 1; } ]=] "HAVE_STRUCT_STATVFS_F_MNTONNAME") file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE_STRUCT_STATVFS_F_MNTONNAME\n") if(HAVE_STRUCT_STATFS_F_MNTONNAME OR HAVE_STRUCT_STATVFS_F_MNTONNAME OR HAVE_STRUCT_MNTENT_MNT_DIR OR HAVE_STRUCT_MNTTAB_MNT_MOUNTP) set(HAVE_MOUNTS 1) file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE_MOUNTS\n") endif() # Emulate ax_random_device.m4 if(EXISTS /dev/urandom) set(RANDOM_DEVICE /dev/urandom) elseif(EXISTS /dev/arandom) set(RANDOM_DEVICE /dev/arandom) elseif(EXISTS /dev/random) set(RANDOM_DEVICE /dev/random) endif() if(RANDOM_DEVICE) set(HAVE_RANDOM_DEVICE TRUE) endif() file(APPEND "${boxconfig_h_file}" "#cmakedefine RANDOM_DEVICE \"${RANDOM_DEVICE}\"\n") file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE_RANDOM_DEVICE\n") # Build an intermediate version of BoxConfig.cmake.h for use in the following tests: configure_file("${boxconfig_h_file}" "${boxconfig_cmake_h_dir}/BoxConfig.cmake.h") # Emulate ax_func_syscall.m4: Autoconf's AC_CHECK_FUNC (which we emulate above, # using check_function_exists) defines the function when testing for its # presence, so HAVE___SYSCALL will be true even if __syscall has no definition # in the system libraries, and this is precisely the case that we want to test # for, so now we test whether a test program compiles with no explicit # definition (only the system headers) and if that fails, we set # HAVE___SYSCALL_NEED_DEFN to 1. CHECK_CXX_SOURCE_COMPILES( [=[ #include "BoxConfig.cmake.h" #ifdef HAVE_SYS_SYSCALL_H # include #endif int main() { __syscall(SYS_exit, 0); return 0; } ]=] HAVE___SYSCALL_NO_DEFN) set(HAVE___SYSCALL_NEED_DEFN !HAVE___SYSCALL_NO_DEFN) file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE___SYSCALL_NEED_DEFN\n") # Build an intermediate version of BoxConfig.cmake.h for use in the following tests: configure_file("${boxconfig_h_file}" "${boxconfig_cmake_h_dir}/BoxConfig.cmake.h") foreach(struct_member_name "struct ucred.uid" "struct ucred.cr_uid") string(REGEX MATCH "(.*)\\.(.*)" dummy_var ${struct_member_name}) set(struct_name "${CMAKE_MATCH_1}") set(member_name "${CMAKE_MATCH_2}") string(TOUPPER "${struct_name}_${member_name}" platform_var_name) string(REGEX REPLACE "[/. ]" "_" platform_var_name ${platform_var_name}) CHECK_CXX_SOURCE_COMPILES([=[ #include "BoxConfig.cmake.h" #ifdef HAVE_UCRED_H # include #endif #ifdef HAVE_SYS_PARAM_H # include #endif #ifdef HAVE_SYS_UCRED_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif int main() { ${struct_name} foo; return sizeof(foo.${member_name}) > 0 ? 0 : 1; } ]=] "HAVE_${platform_var_name}") file(APPEND "${boxconfig_h_file}" "#cmakedefine HAVE_${platform_var_name}\n") endforeach() function(AX_TRY_RUN_FD code var) CHECK_CXX_SOURCE_RUNS([=[ #include "BoxConfig.cmake.h" #include #include #include #include #ifdef HAVE___SYSCALL_NEED_DEFN extern "C" off_t __syscall(quad_t number, ...); #endif #ifdef HAVE___SYSCALL // always use it if we have it # undef syscall # define syscall __syscall #endif int main() { int fd = creat("lseektest", 0600); int res = 1; if(fd>=0) { ${code} close(fd); } unlink("lseektest"); return res; } ]=] ${var}) file(APPEND "${boxconfig_h_file}" "#cmakedefine ${var}\n") endfunction() AX_TRY_RUN_FD( [=[ // This test tries first to seek to position 0, with NO "dummy // argument". If lseek does actually require a dummy argument, // then it will eat SEEK_SET for the offset and try to use 99 // as whence, which is invalid, so res will be 0, the program // will return 0 and we will define HAVE_LSEEK_DUMMY_PARAM // (whew! that took 1 hour to figure out) The "dummy argument" // probably means that it takes a 64-bit offset. res = (syscall(SYS_lseek, fd, (int32_t)10, SEEK_SET, 99) == 10) ? 2 : 0; ]=] HAVE_LSEEK_DUMMY_PARAM) AX_TRY_RUN_FD( [=[ // Try to seek to a position that requires a 64-bit // representation, and check the return value, which is the // current position. if(syscall(SYS_lseek, fd, (int64_t)5, SEEK_SET) != 5) { res = 2; } else if(syscall(SYS_lseek, fd, (int64_t)10, SEEK_CUR) != 15) { res = 3; } else { res = 0; } ]=] HAVE_LSEEK_64_BIT) set(CMAKE_REQUIRED_INCLUDES "") # Build the final version of BoxConfig.cmake.h, as a temporary file. configure_file("${boxconfig_h_file}" "${boxconfig_cmake_h_dir}/BoxConfig.cmake.h.new") # Move the original back into place, and then replace it with the # temporary one if different (which will force a rebuild of everything). move_file_if_exists( "${boxconfig_cmake_h_dir}/BoxConfig.cmake.h.bak" "${boxconfig_cmake_h_dir}/BoxConfig.cmake.h") replace_file_if_different( "${boxconfig_cmake_h_dir}/BoxConfig.cmake.h" "${boxconfig_cmake_h_dir}/BoxConfig.cmake.h.new") # Tell QDBM not to build itself as a DLL, because we want to link statically to it. target_compile_definitions(qdbm PUBLIC -DQDBM_STATIC) # Silence some less-useful warnings if(MSVC) add_definitions(/wd4291 /wd4710 /wd4820 /wd4996) set_property(TARGET qdbm PROPERTY CMAKE_STATIC_LINKER_FLAGS /IGNORE:LNK4006) endif(MSVC) # Define the location of the Perl executable, needed by testbackupstorefix file(TO_NATIVE_PATH "${PERL_EXECUTABLE}" perl_executable_native) string(REPLACE "\\" "\\\\" perl_path_escaped ${perl_executable_native}) target_compile_definitions(test_backupstorefix PRIVATE -DPERL_EXECUTABLE="${perl_path_escaped}") # Configure test timeouts: # I've set the timeout to 4 times as long as it took to run on a particular run on Appveyor: # https://ci.appveyor.com/project/qris/boxbackup/build/job/xm10itascygtu93j set_tests_properties(common PROPERTIES TIMEOUT 20) set_tests_properties(crypto PROPERTIES TIMEOUT 10) set_tests_properties(compress PROPERTIES TIMEOUT 80) set_tests_properties(raidfile PROPERTIES TIMEOUT 32) set_tests_properties(basicserver PROPERTIES TIMEOUT 80) set_tests_properties(backupstore PROPERTIES TIMEOUT 1320) set_tests_properties(backupstorefix PROPERTIES TIMEOUT 180) set_tests_properties(backupstorepatch PROPERTIES TIMEOUT 320) set_tests_properties(backupdiff PROPERTIES TIMEOUT 32) set_tests_properties(bbackupd PROPERTIES TIMEOUT 1200) set_tests_properties(s3store PROPERTIES TIMEOUT 20) set_tests_properties(httpserver PROPERTIES TIMEOUT 40) set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Box Backup is an open source, completely automatic, on-line backup system") set(CPACK_PACKAGE_VENDOR "www.BoxBackup.org") set(CPACK_PACKAGE_DESCRIPTION_FILE "${base_dir}/README.md") set(CPACK_RESOURCE_FILE_LICENSE "${base_dir}/LICENSE.txt") set(CPACK_PACKAGE_VERSION ${boxbackup_version}) set(CPACK_PACKAGE_INSTALL_DIRECTORY "Box Backup") set(CPACK_COMPONENTS_ALL Applications Extras) set(CPACK_GENERATOR "ZIP;NSIS") set(CPACK_NSIS_DISPLAY_NAME "Box Backup") set(CPACK_NSIS_HELP_LINK "http://www.boxbackup.org/") set(CPACK_NSIS_URL_INFO_ABOUT "http://www.boxbackup.org/") set(CPACK_NSIS_CONTACT "boxbackup@boxbackup.org") set(CPACK_NSIS_MODIFY_PATH ON) include(CPack)