summaryrefslogtreecommitdiff
path: root/infrastructure
diff options
context:
space:
mode:
authorChris Wilson <chris+github@qwirx.com>2016-09-03 00:25:52 +0100
committerChris Wilson <chris+github@qwirx.com>2016-09-09 20:54:12 +0100
commit98a6ad72ee819774a398440055abd87bc44e9ba0 (patch)
tree55a5c7eff8deaab2ab7d44ed0357576aa0687a96 /infrastructure
parent11a8c444875d8b7912fa07bdc3854e3adb27aa4e (diff)
Fix Unix compilation using CMake.
Add platform detection that's compatible with the old buildsystem and its m4 autoconfigury. Make Travis build and test using CMake as a separate target. Remove unused function BoxGetTemporaryDirectoryName() to fixes compile using CMake on Unix.
Diffstat (limited to 'infrastructure')
-rw-r--r--infrastructure/cmake/CMakeLists.txt289
-rwxr-xr-xinfrastructure/cmake/getversion.pl13
-rwxr-xr-xinfrastructure/travis-build.sh30
3 files changed, 305 insertions, 27 deletions
diff --git a/infrastructure/cmake/CMakeLists.txt b/infrastructure/cmake/CMakeLists.txt
index 0838045a..fa364690 100644
--- a/infrastructure/cmake/CMakeLists.txt
+++ b/infrastructure/cmake/CMakeLists.txt
@@ -75,24 +75,31 @@ foreach(file_to_configure ${files_to_configure})
configure_file("${base_dir}/${file_to_configure}.in" "${base_dir}/${file_to_configure}" @ONLY)
endforeach()
-file(READ "${base_dir}/infrastructure/buildenv-testmain-template.cpp" test_template)
-
-
+# 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/msvc/getversion.pl
+ COMMAND ${PERL_EXECUTABLE} ${base_dir}/infrastructure/cmake/getversion.pl
+ WORKING_DIRECTORY ${base_dir}/infrastructure
RESULT_VARIABLE status
- OUTPUT_VARIABLE command_output
+ OUTPUT_VARIABLE new_version_define
ERROR_VARIABLE command_output)
if(NOT status EQUAL 0)
message(FATAL_ERROR "Failed to execute: "
- "${PERL_EXECUTABLE} ${base_dir}/infrastructure/msvc/getversion.pl: "
+ "${PERL_EXECUTABLE} ${base_dir}/infrastructure/cmake/getversion.pl: "
"status ${status}: ${command_output}")
endif()
+file(WRITE "${base_dir}/lib/common/BoxVersion.h.new" "${new_version_define}")
+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()
+file(READ "${base_dir}/infrastructure/buildenv-testmain-template.cpp" test_template)
+
# Parsing Makefile.extra files in CMake script is a pain, so the relevant rules for
# code-generating Perl scripts are hard-coded here.
@@ -322,19 +329,24 @@ endforeach()
# 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 $<$<CONFIG:Release>:-DBOX_RELEASE_BUILD>)
+target_compile_definitions(lib_common PUBLIC $<$<CONFIG:Release>:BOX_RELEASE_BUILD>)
-# Tell QDBM not to build itself as a DLL, because we want to link statically to it.
-target_compile_definitions(qdbm PUBLIC -DQDBM_STATIC)
+# Detect platform features and write BoxConfig.h.in. Reuse code from
+# infrastructure/m4/boxbackup_tests.m4 where possible
-# Silence some less-useful warnings
-if(MSVC)
- add_definitions(/wd4996 /wd4291)
- # target_link_libraries(qdbm PRIVATE /IGNORE:LNK4006)
- set_property(TARGET qdbm PROPERTY CMAKE_STATIC_LINKER_FLAGS /IGNORE:LNK4006)
-endif(MSVC)
+include(CheckIncludeFiles)
+include(CheckFunctionExists)
+include(CheckSymbolExists)
+include(CheckLibraryExists)
+include(CheckCXXSourceCompiles)
-target_link_libraries(lib_common PUBLIC ws2_32 gdi32)
+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()
# Link to ZLib
# http://stackoverflow.com/a/6174604/648162
@@ -406,6 +418,251 @@ if(READLINE_FOUND)
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[_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")
+ 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 <sys/param.h>
+ #endif
+ #include <sys/mount.h>
+ 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 <sys/param.h>
+ #endif
+ #include <sys/mount.h>
+ 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")
+
+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 <ucred.h>
+ #endif
+
+ #ifdef HAVE_SYS_PARAM_H
+ # include <sys/param.h>
+ #endif
+
+ #ifdef HAVE_SYS_UCRED_H
+ # include <sys/ucred.h>
+ #endif
+
+ #ifdef HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
+ #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()
+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(/wd4996 /wd4291)
+ 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})
diff --git a/infrastructure/cmake/getversion.pl b/infrastructure/cmake/getversion.pl
new file mode 100755
index 00000000..67e1f8a5
--- /dev/null
+++ b/infrastructure/cmake/getversion.pl
@@ -0,0 +1,13 @@
+#!perl
+
+use File::Basename;
+$basedir = dirname($0)."/../..";
+
+-d $basedir or die "Base directory $basedir does not exist!";
+chdir $basedir or die "Failed to change to base directory: $basedir: $!";
+
+require "$basedir/infrastructure/BoxPlatform.pm.in";
+
+print "#define BOX_VERSION \"$BoxPlatform::product_version\"\n";
+
+exit 0;
diff --git a/infrastructure/travis-build.sh b/infrastructure/travis-build.sh
index aa9f62c2..72a187b3 100755
--- a/infrastructure/travis-build.sh
+++ b/infrastructure/travis-build.sh
@@ -5,17 +5,25 @@ set -x
ccache -s
-cd `dirname $0`/..
-./bootstrap
-./configure CC="ccache $CC" CXX="ccache $CXX" "$@"
-grep CXX config.status
-make V=1
-./runtest.pl ALL $TEST_TARGET
-# When making a release build, also check that we can build the default
-# target and "parcels" (which is the same thing):
-if [ "$TEST_TARGET" = "release" ]; then
- make
- make parcels
+if [ "$BUILD" = 'cmake' ]; then
+ cd `dirname $0`
+ mkdir -p cmake/build
+ cd cmake/build
+ cmake --version
+ cmake -DCMAKE_BUILD_TYPE:STRING=$TEST_TARGET ..
+ make install
+ [ "$TEST" = "n" ] || ctest -C $TEST_TARGET -V
+else
+ cd `dirname $0`/..
+ ./bootstrap
+ ./configure CC="ccache $CC" CXX="ccache $CXX" "$@"
+ grep CXX config.status
+ make V=1
+ ./runtest.pl ALL $TEST_TARGET
+ if [ "$TEST_TARGET" = "release" ]; then
+ make
+ make parcels
+ fi
fi
ccache -s