cmake_minimum_required(VERSION 2.8.10) # Default install location. Must be set here, before setting the project. if (NOT DEFINED CMAKE_INSTALL_PREFIX) set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "" FORCE) endif() set(PROJECT unity-scopes-api) project(${PROJECT} C CXX) if(${PROJECT_BINARY_DIR} STREQUAL ${PROJECT_SOURCE_DIR}) message(FATAL_ERROR "In-tree build attempt detected, aborting. Set your build dir outside your source dir, delete CMakeCache.txt from source root and try again.") endif() include(CheckCXXSourceCompiles) CHECK_CXX_SOURCE_COMPILES("#ifdef __clang__\n#else\n#error \"Not clang.\"\n#endif\nint main(int argc, char **argv) { return 0; }" IS_CLANG) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) if(IS_CLANG) message(STATUS "Compiling with Clang, disabling lttng.") endif() string(TOLOWER "${CMAKE_BUILD_TYPE}" cmake_build_type_lower) # Build types should always be lowercase but sometimes they are not. set(ACCEPTED_BUILD_TYPES "" none release debug relwithdebinfo coverage) list(FIND ACCEPTED_BUILD_TYPES "${cmake_build_type_lower}" IS_BUILD_TYPE_ACCEPTED) if(${IS_BUILD_TYPE_ACCEPTED} EQUAL -1) message(FATAL_ERROR "Invalid CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}\nValid types are: ${ACCEPTED_BUILD_TYPES}") endif() # Static C++ checks find_program(CPPCHECK_COMMAND NAMES cppcheck) if (CPPCHECK_COMMAND) set(CPPCHECK_COMMAND_OPTIONS --check-config --inline-suppr --enable=all -q --error-exitcode=2) set(CPPCHECK_COMMAND_OPTIONS ${CPPCHECK_COMMAND_OPTIONS} --template "'{file}({line}): {severity} ({id}): {message}'") add_custom_target(cppcheck COMMAND ${CPPCHECK_COMMAND} ${CPPCHECK_COMMAND_OPTIONS} ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/test ${CMAKE_BINARY_DIR}/test ) else() message(WARNING "Cannot find cppcheck: cppcheck target will not be available") endif() # # Definitions for testing with valgrind. # configure_file(CTestCustom.cmake.in CTestCustom.cmake) # Tests in CTestCustom.cmake are skipped for valgrind find_program(MEMORYCHECK_COMMAND NAMES valgrind) if (MEMORYCHECK_COMMAND) set(MEMORYCHECK_COMMAND_OPTIONS "--suppressions=${CMAKE_SOURCE_DIR}/valgrind-suppress --leak-check=full --num-callers=40 --error-exitcode=3" ) add_custom_target(valgrind DEPENDS NightlyMemCheck) else() message(WARNING "Cannot find valgrind: valgrind target will not be available") endif() include(FindPkgConfig) find_package(Boost COMPONENTS system filesystem regex serialization thread log REQUIRED) pkg_check_modules(UNITY_API libunity-api>=0.1.3 REQUIRED) pkg_check_modules(PROCESS_CPP process-cpp>=1.0.1 REQUIRED) pkg_check_modules(APPARMOR REQUIRED libapparmor REQUIRED) pkg_check_modules(LTTNG_UST lttng-ust REQUIRED) pkg_check_modules(LIBURCU_BP liburcu-bp REQUIRED) pkg_check_modules(JSONCPP jsoncpp REQUIRED) pkg_check_modules(LIBACCOUNTS libaccounts-glib REQUIRED) pkg_check_modules(LIBSIGNON libsignon-glib REQUIRED) pkg_check_modules(ZMQLIB libzmq REQUIRED) pkg_check_modules(NET_CPP net-cpp>=1.2.0 REQUIRED) find_library(ZMQPPLIB zmqpp) if(NOT ZMQPPLIB) message(FATAL_ERROR "libzmqpp-dev not found.") endif() find_library(CAPNPLIB capnp) if(NOT CAPNPLIB) message(FATAL_ERROR "libcapnp-dev not found.") endif() find_library(KJLIB kj) if(NOT KJLIB) message(FATAL_ERROR "capnproto not found.") endif() find_library(DLLIB dl) if(NOT DLLIB) message(FATAL_ERROR "dl lib not found.") endif() find_program(LTTNG_EXECUTABLE lttng) if (NOT LTTNG_EXECUTABLE) message(SEND_ERROR "Cannot find LTTng executable: ensure that lttng-tools is installed") endif() # # Code style fixer. We put the code through astyle first because it makes some fixes that # clang-format won't do (such as "char *p" -> "char* p"). But astyle messes up other things # (particularly lambdas and assembly-style comments), which clang-format does right. # So, we run clang-format after running astyle, which undoes the damage done by astyle # without reverting desirable astyle fixes. # find_program(ASTYLE_COMMAND NAMES astyle) if (NOT ASTYLE_COMMAND) message(WARNING "Cannot find astyle: formatcode target will not be available") else() # astyle 2.03 creates DOS line endings, so we need to fix its output find_program(DOS2UNIX_COMMAND NAMES dos2unix) if (NOT DOS2UNIX_COMMAND) message(WARNING "Cannot find dos2unix: formatcode target will not be available") else() find_program(CLANG_FORMAT_COMMAND NAMES clang-format-3.6 clang-format-3.5) if (NOT CLANG_FORMAT_COMMAND) message(WARNING "Cannot find clang-format >= clang-format-3.5: formatcode target will not be available") endif() endif() endif() if (ASTYLE_COMMAND AND DOS2UNIX_COMMAND AND CLANG_FORMAT_COMMAND) set(UNITY_SCOPES_LIB_HDRS ${UNITY_SCOPES_LIB_HDRS} ${fmt_h}) add_custom_target(formatcode ${PROJECT_SOURCE_DIR}/tools/format-files.sh ${PROJECT_SOURCE_DIR} ${ASTYLE_COMMAND} ${CLANG_FORMAT_COMMAND}) endif() find_program(CAPNPC_BIN capnpc) if(NOT CAPNPC_BIN) message(FATAL_ERROR "Capnp compiler not found.") endif() set(CAPNPC_FLAGS "" CACHE STRING "Extra flags for capnpc.") add_definitions( -DDEB_HOST_MULTIARCH="${CMAKE_LIBRARY_ARCHITECTURE}" ) set(OTHER_INCLUDE_DIRS ${OTHER_INCLUDE_DIRS} ${UNITY_API_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${JSONCPP_INCLUDE_DIRS} ${PROCESS_CPP_INCLUDE_DIRS} ${APPARMOR_INCLUDE_DIRS} ${LIBACCOUNTS_INCLUDE_DIRS} ${LIBSIGNON_INCLUDE_DIRS} ${NET_CPP_INCLUDE_DIRS}) set(OTHER_LIBS ${OTHER_LIBS} ${UNITY_API_LDFLAGS} ${APPARMOR_LDFLAGS} ${LIBACCOUNTS_LIBRARIES} ${LIBSIGNON_LIBRARIES} ${Boost_LIBRARIES} ${JSONCPP_LDFLAGS} ${PROCESS_CPP_LDFLAGS} ${ZMQPPLIB} ${ZMQLIB_LDFLAGS} ${CAPNPLIB} ${KJLIB} ${DLLIB} ${NET_CPP_LDFLAGS} pthread) # Standard install paths include(GNUInstallDirs) include_directories( include/ ${CMAKE_BINARY_DIR}/include ${CMAKE_BINARY_DIR}/src ${OTHER_INCLUDE_DIRS} ) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -Wno-variadic-macros -Wextra -fPIC") # By default, all symbols are visible in the library. We strip out things we don't # want at link time, by running a version script (see unity-scopes.map and the # setting of LINK_FLAGS below). set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default") set(C_AND_CXX_WARNINGS "-pedantic -Wall -Wextra") # Some additional warnings not included by the general flags set above. set(EXTRA_C_WARNINGS "-Wcast-align -Wcast-qual -Wformat -Wredundant-decls -Wswitch-default") set(EXTRA_CXX_WARNINGS "-Wnon-virtual-dtor -Wctor-dtor-privacy -Wold-style-cast") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_AND_CXX_WARNINGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_C_WARNINGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${C_AND_CXX_WARNINGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_C_WARNINGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXX_WARNINGS}") # -fno-permissive causes warnings with clang, so we only enable it for gcc if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-permissive") endif() if ("${cmake_build_type_lower}" STREQUAL "release" OR "${cmake_build_type_lower}" STREQUAL "relwithdebinfo") option(Werror "Treat warnings as errors" ON) else() option(Werror "Treat warnings as errors" OFF) endif() # Some tests are slow, so make it possible not to run them during day-to-day development. # The default for this *must* stay ON, otherwise the tests won't run in Jenkins. option(slowtests "Run slow tests" ON) if (${Werror}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") if ("${cmake_build_type_lower}" STREQUAL "release" OR "${cmake_build_type_lower}" STREQUAL "relwithdebinfo") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=deprecated-declarations") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=deprecated-declarations") endif() endif() set(SANITIZER "" CACHE STRING "Build with -fsanitize= (legal values: thread, address)") if ("${SANITIZER}" STREQUAL "") # Do nothing elseif (${SANITIZER} STREQUAL "thread") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -fno-omit-frame-pointer") elseif (${SANITIZER} STREQUAL "address") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") else() message(FATAL_ERROR "Invalid SANITIZER setting: ${SANITIZER}") endif() # Scopes library names. Also used as a prefix in various places, and as a subdirectory # name for installed files. Changing this will also require corresponding changes # to the debian files. set(UNITY_SCOPES_LIB unity-scopes) set(UNITY_SCOPES_QT_LIB unity-scopes-qt) # Run debian/get-versions.sh to get the version and soversion numbers for each library. execute_process(COMMAND mktemp -d OUTPUT_VARIABLE version_dir OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process(COMMAND sh ${CMAKE_SOURCE_DIR}/debian/get-versions.sh ${CMAKE_SOURCE_DIR}/debian ${version_dir}) # Set versions for libunity-scopes. file(READ ${version_dir}/lib${UNITY_SCOPES_LIB}.full-version UNITY_SCOPES_FULL_VERSION) string(STRIP ${UNITY_SCOPES_FULL_VERSION} UNITY_SCOPES_FULL_VERSION) file(READ ${version_dir}/lib${UNITY_SCOPES_LIB}.major-version UNITY_SCOPES_MAJOR) string(STRIP ${UNITY_SCOPES_MAJOR} UNITY_SCOPES_MAJOR) file(READ ${version_dir}/lib${UNITY_SCOPES_LIB}.minor-version UNITY_SCOPES_MINOR) string(STRIP ${UNITY_SCOPES_MINOR} UNITY_SCOPES_MINOR) file(READ ${version_dir}/lib${UNITY_SCOPES_LIB}.micro-version UNITY_SCOPES_MICRO) string(STRIP ${UNITY_SCOPES_MICRO} UNITY_SCOPES_MICRO) file(READ ${version_dir}/lib${UNITY_SCOPES_LIB}.major-minor-version UNITY_SCOPES_MAJOR_MINOR) string(STRIP ${UNITY_SCOPES_MAJOR_MINOR} UNITY_SCOPES_MAJOR_MINOR) file(READ ${version_dir}/lib${UNITY_SCOPES_LIB}.soversion UNITY_SCOPES_SOVERSION) string(STRIP ${UNITY_SCOPES_SOVERSION} UNITY_SCOPES_SOVERSION) # Set versions for libunity-scopes-qt. file(READ ${version_dir}/lib${UNITY_SCOPES_QT_LIB}.full-version UNITY_SCOPES_QT_FULL_VERSION) string(STRIP ${UNITY_SCOPES_QT_FULL_VERSION} UNITY_SCOPES_QT_FULL_VERSION) file(READ ${version_dir}/lib${UNITY_SCOPES_QT_LIB}.major-version UNITY_SCOPES_QT_MAJOR) string(STRIP ${UNITY_SCOPES_QT_MAJOR} UNITY_SCOPES_QT_MAJOR) file(READ ${version_dir}/lib${UNITY_SCOPES_QT_LIB}.minor-version UNITY_SCOPES_QT_MINOR) string(STRIP ${UNITY_SCOPES_QT_MINOR} UNITY_SCOPES_QT_MINOR) file(READ ${version_dir}/lib${UNITY_SCOPES_QT_LIB}.micro-version UNITY_SCOPES_QT_MICRO) string(STRIP ${UNITY_SCOPES_QT_MICRO} UNITY_SCOPES_QT_MICRO) file(READ ${version_dir}/lib${UNITY_SCOPES_QT_LIB}.major-minor-version UNITY_SCOPES_QT_MAJOR_MINOR) string(STRIP ${UNITY_SCOPES_QT_MAJOR_MINOR} UNITY_SCOPES_QT_MAJOR_MINOR) file(READ ${version_dir}/lib${UNITY_SCOPES_QT_LIB}.soversion UNITY_SCOPES_QT_SOVERSION) string(STRIP ${UNITY_SCOPES_QT_SOVERSION} UNITY_SCOPES_QT_SOVERSION) if(NOT ${UNITY_SCOPES_MAJOR} EQUAL 1) message(FATAL_ERROR "Change in major version number. You need to adjust get-versions.sh and gen-debian-files.sh") endif() if(NOT ${UNITY_SCOPES_QT_MAJOR} EQUAL 0) message(FATAL_ERROR "Change in Qt major version number. You need to adjust get-versions.sh and gen-debian-files.sh") endif() # Library for testing, with all symbols visible set(UNITY_SCOPES_TEST_LIB ${UNITY_SCOPES_LIB}-test) # All the libraries we need to link a normal executable that uses Unity scopes set(LIBS ${UNITY_SCOPES_LIB}) # Test version of ${UNITY_SCOPES_LIB}, with internal symbols visible set(TESTLIBS ${UNITY_SCOPES_TEST_LIB}) # Library install prefix set(LIB_INSTALL_PREFIX lib/${CMAKE_LIBRARY_ARCHITECTURE}) set(LIBDIR ${CMAKE_INSTALL_LIBDIR}) set(LIBSUBDIR ${LIBDIR}/${UNITY_SCOPES_LIB}}) set(HDR_INSTALL_DIR include/${UNITY_SCOPES_LIB}-${UNITY_SCOPES_SOVERSION}) ##################################################################### # Enable code coverage calculation with gcov/gcovr/lcov # Usage: # * Switch build type to coverage (use ccmake or cmake-gui) # * Invoke make, make test, make coverage (or ninja if you use that backend) # * Find html report in subdir coveragereport # * Find xml report suitable for jenkins in coverage.xml ##################################################################### if(cmake_build_type_lower MATCHES coverage) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -g") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage -g") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} --coverage -g") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --coverage -g") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage -g") endif() include(EnableCoverageReport) # Tests include(CTest) enable_testing() # Add subdirectories. add_subdirectory(include) add_subdirectory(src) add_subdirectory(scoperegistry) add_subdirectory(scoperunner) add_subdirectory(smartscopesproxy) add_subdirectory(data) add_subdirectory(test) add_subdirectory(demo) add_subdirectory(tools) # Custom rules to compile .capnp files foreach(file ${CAPNPROTO_FILES}) string(REPLACE "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" build_dir ${file}) get_filename_component(build_dir ${build_dir} PATH) get_filename_component(proto_file ${file} NAME) string(REPLACE ".capnp" ".capnp.c++" src_file ${proto_file}) string(REPLACE ".capnp" ".capnp.h" hdr_file ${proto_file}) set(src_file ${build_dir}/${src_file}) set(hdr_file ${build_dir}/${hdr_file}) set(CAPNPROTO_HDRS ${CAPNPROTO_HDRS} ${hdr_file}) set(CAPNPROTO_SRC ${CAPNPROTO_SRC} ${src_file}) endforeach() # cmake cannot analyze include file dependencies of .capnproto files, so the easiest option is to recompile # all files if any one of them changes add_custom_command(OUTPUT ${CAPNPROTO_SRC} ${CAPNPROTO_HDRS} DEPENDS ${CAPNPROTO_FILES} COMMAND ${CAPNPC_BIN} ${CAPNPC_FLAGS} -oc++:${CMAKE_BINARY_DIR} --src-prefix=${CMAKE_SOURCE_DIR} ${CAPNPROTO_FILES}) # Pseudo-library of object files. We need a version of the library for normal clients # that does not expose symbols in the unity::scopes::internal namespace, and another # version for whitebox tests, so we can write unit tests for classes in the internal namespaces. # Here, we create an object library that then is used to link the normal and the test libraries. set(UNITY_SCOPES_LIB_OBJ ${UNITY_SCOPES_LIB}-obj) add_library(${UNITY_SCOPES_LIB_OBJ} OBJECT ${UNITY_SCOPES_LIB_SRC} ${CAPNPROTO_SRC}) set_target_properties(${UNITY_SCOPES_LIB_OBJ} PROPERTIES COMPILE_FLAGS "-fPIC") # Use the object files to make the normal library. add_library(${UNITY_SCOPES_LIB} SHARED $) set_target_properties(${UNITY_SCOPES_LIB} PROPERTIES VERSION ${UNITY_SCOPES_FULL_VERSION} SOVERSION ${UNITY_SCOPES_SOVERSION} ) # Use the object files to make the test library. add_library(${UNITY_SCOPES_TEST_LIB} SHARED $) set_target_properties(${UNITY_SCOPES_TEST_LIB} PROPERTIES VERSION ${UNITY_SCOPES_FULL_VERSION} SOVERSION ${UNITY_SCOPES_SOVERSION} ) set(ldflags "") # Clang sanitizers don't work if --no-undefined is given as a linker argument. if(NOT IS_CLANG) set(ldflags "-Wl,--no-undefined") endif() set_target_properties(${UNITY_SCOPES_TEST_LIB} PROPERTIES LINK_FLAGS "${ldflags}") # We compile with all symbols visible by default. For the shipping library, we strip # out all symbols that (recursively) are in the unity::scopes::internal namespace, # except for a few exceptions that are needed by the scoperegistry, scoperunner, # smartscopesproxy, and any other binaries that reach into the internal namespace. set(symbol_map "${CMAKE_SOURCE_DIR}/${UNITY_SCOPES_LIB}.map") set_target_properties(${UNITY_SCOPES_LIB} PROPERTIES LINK_FLAGS "${ldflags} -Wl,--version-script,${symbol_map}") set_target_properties(${UNITY_SCOPES_LIB} PROPERTIES LINK_DEPENDS ${symbol_map}) target_link_libraries(${UNITY_SCOPES_LIB} ${OTHER_LIBS}) target_link_libraries(${UNITY_SCOPES_TEST_LIB} ${OTHER_LIBS}) # Only the normal library gets installed. install(TARGETS ${UNITY_SCOPES_LIB} LIBRARY DESTINATION ${LIB_INSTALL_PREFIX}) # Enable coverage testing if (cmake_build_type_lower MATCHES coverage) ENABLE_COVERAGE_REPORT(TARGETS ${UNITY_SCOPES_LIB} FILTER /usr/include ${CMAKE_SOURCE_DIR}/test/* ${CMAKE_SOURCE_DIR}/debian/tests/* ${CMAKE_SOURCE_DIR}/demo/* ${CMAKE_BINARY_DIR}/*) endif() # # Documentation # # Pass -DDEVEL_DOCS=ON to cmake for more detailed documentation option(DEVEL_DOCS "Enable detailed Doxygen documentation") find_package(Doxygen) find_program(DOT_EXECUTABLE dot /usr/bin) if (NOT DOXYGEN_FOUND OR NOT DOT_EXECUTABLE) message(WARNING "Cannot generate documentation: doxygen and/or graphviz not found") else() if (DEVEL_DOCS) message(STATUS "Creating devel documentation") configure_file(${PROJECT_SOURCE_DIR}/doc/Doxyfile-devel.in ${PROJECT_BINARY_DIR}/doc/Doxyfile @ONLY IMMEDIATE) else() configure_file(${PROJECT_SOURCE_DIR}/doc/Doxyfile.in ${PROJECT_BINARY_DIR}/doc/Doxyfile @ONLY IMMEDIATE) endif() configure_file(${PROJECT_SOURCE_DIR}/doc/index.html ${PROJECT_BINARY_DIR}/doc/index.html COPYONLY) add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/doc/${UNITY_SCOPES_LIB}/index.html COMMAND ${DOXYGEN_EXECUTABLE} ${PROJECT_BINARY_DIR}/doc/Doxyfile DEPENDS ${PROJECT_BINARY_DIR}/doc/Doxyfile ${PROJECT_SOURCE_DIR}/doc/tutorial.dox ${UNITY_SCOPES_LIB_SRC} ${UNITY_SCOPES_LIB_HDRS}) add_custom_target(doc ALL DEPENDS ${PROJECT_BINARY_DIR}/doc/${UNITY_SCOPES_LIB}/index.html) install(DIRECTORY ${PROJECT_BINARY_DIR}/doc/${UNITY_SCOPES_LIB} DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/doc) endif()