From a0e28467f9c87333ac5b0b4f13b9999ea6903605 Mon Sep 17 00:00:00 2001 From: onqtam Date: Sat, 10 Sep 2016 01:37:53 +0300 Subject: Using a CMake function called "doctest_force_link_static_lib_in_target" located in "doctest_force_link_static_lib_in_target.cmake" users of CMake can force the linking of every object file from a static library to an executable/shared target. Not intrusive - using generated dummy headers in the build folder of the target, CMake target properties and compiler flags for including the headers to the appropriate sources. fixes #21 --- examples/exe_with_static_libs/CMakeLists.txt | 23 +++++ .../doctest_force_link_static_lib_in_target.cmake | 107 +++++++++++++++++++++ examples/exe_with_static_libs/lib_1_src1.cpp | 4 + examples/exe_with_static_libs/lib_1_src2.cpp | 4 + examples/exe_with_static_libs/lib_2_src.cpp | 4 + examples/exe_with_static_libs/main.cpp | 4 + .../test_output/exe_with_static_libs.txt | 9 ++ 7 files changed, 155 insertions(+) create mode 100644 examples/exe_with_static_libs/CMakeLists.txt create mode 100644 examples/exe_with_static_libs/doctest_force_link_static_lib_in_target.cmake create mode 100644 examples/exe_with_static_libs/lib_1_src1.cpp create mode 100644 examples/exe_with_static_libs/lib_1_src2.cpp create mode 100644 examples/exe_with_static_libs/lib_2_src.cpp create mode 100644 examples/exe_with_static_libs/main.cpp create mode 100644 examples/exe_with_static_libs/test_output/exe_with_static_libs.txt (limited to 'examples') diff --git a/examples/exe_with_static_libs/CMakeLists.txt b/examples/exe_with_static_libs/CMakeLists.txt new file mode 100644 index 0000000..bd3d32a --- /dev/null +++ b/examples/exe_with_static_libs/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 2.8) + +get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) +project(${PROJECT_NAME}) + +include(../../scripts/common.cmake) + +include_directories("../../doctest/") + +add_library(lib_1 STATIC lib_1_src1.cpp lib_1_src2.cpp) +add_library(lib_2 STATIC lib_2_src.cpp) + +add_executable(${PROJECT_NAME} main.cpp) +target_link_libraries(${PROJECT_NAME} lib_1) +target_link_libraries(${PROJECT_NAME} lib_2) + +add_test(NAME ${PROJECT_NAME} COMMAND $) + +# pulls the force linking functionality +include(doctest_force_link_static_lib_in_target.cmake) + +doctest_force_link_static_lib_in_target(${PROJECT_NAME} lib_1) +doctest_force_link_static_lib_in_target(${PROJECT_NAME} lib_2) diff --git a/examples/exe_with_static_libs/doctest_force_link_static_lib_in_target.cmake b/examples/exe_with_static_libs/doctest_force_link_static_lib_in_target.cmake new file mode 100644 index 0000000..b937aec --- /dev/null +++ b/examples/exe_with_static_libs/doctest_force_link_static_lib_in_target.cmake @@ -0,0 +1,107 @@ +if(doctest_force_link_static_lib_in_target_included) + return() +endif() +set(doctest_force_link_static_lib_in_target_included true) + +# includes the file to the source with compiler flags +function(doctest_include_file_in_sources header sources) + foreach(src ${sources}) + if(${src} MATCHES \\.\(cc|cp|cpp|CPP|c\\+\\+|cxx\)$) + # get old flags + get_source_file_property(old_compile_flags ${src} COMPILE_FLAGS) + if(old_compile_flags STREQUAL "NOTFOUND") + set(old_compile_flags "") + endif() + + # update flags + if(MSVC) + set_source_files_properties(${src} PROPERTIES COMPILE_FLAGS + "${old_compile_flags} /FI\"${header}\"") + else() + set_source_files_properties(${src} PROPERTIES COMPILE_FLAGS + "${old_compile_flags} -include \"${header}\"") + endif() + endif() + endforeach() +endfunction() + +# this is the magic function - forces every object file from the library to be linked into the target (dll or executable) +function(doctest_force_link_static_lib_in_target target lib) + # check if the library has generated dummy headers + get_target_property(DDH ${lib} DOCTEST_DUMMY_HEADER) + get_target_property(LIB_NAME ${lib} NAME) + if(${DDH} STREQUAL "DDH-NOTFOUND") + # figure out the paths and names of the dummy headers - should be in the build folder for the target + get_target_property(BD ${lib} BINARY_DIR) + set(dummy_dir ${BD}/${LIB_NAME}_DOCTEST_STATIC_LIB_FORCE_LINK_DUMMIES/) + set(dummy_header ${dummy_dir}/all_dummies.h) + file(MAKE_DIRECTORY ${dummy_dir}) + + # create a dummy header for each source file, include a dummy function in it and include it in the source file + set(curr_dummy "0") + set(DLL_PRIVATE "#ifndef _WIN32\n#define DLL_PRIVATE __attribute__ ((visibility (\"hidden\")))\n#else\n#define DLL_PRIVATE\n#endif\n\n") + get_target_property(lib_sources ${lib} SOURCES) + foreach(src ${lib_sources}) + if(${src} MATCHES \\.\(cc|cp|cpp|CPP|c\\+\\+|cxx\)$) + math(EXPR curr_dummy "${curr_dummy} + 1") + + set(curr_dummy_header ${dummy_dir}/dummy_${curr_dummy}.h) + file(WRITE ${curr_dummy_header} "${DLL_PRIVATE}namespace doctest { namespace detail { DLL_PRIVATE int dummy_for_${LIB_NAME}_${curr_dummy}(); DLL_PRIVATE int dummy_for_${LIB_NAME}_${curr_dummy}() { return ${curr_dummy}; } } }") + doctest_include_file_in_sources(${curr_dummy_header} ${src}) + endif() + endforeach() + set(total_dummies ${curr_dummy}) + + # create the master dummy header + file(WRITE ${dummy_header} "${DLL_PRIVATE}namespace doctest { namespace detail {\n\n") + + # forward declare the dummy functions in the master dummy header + foreach(curr_dummy RANGE 1 ${total_dummies}) + file(APPEND ${dummy_header} "DLL_PRIVATE int dummy_for_${LIB_NAME}_${curr_dummy}();\n") + endforeach() + + # call the dummy functions in the master dummy header + file(APPEND ${dummy_header} "\nDLL_PRIVATE int dummies_for_${LIB_NAME}();\nDLL_PRIVATE int dummies_for_${LIB_NAME}() {\n int res = 0;\n") + foreach(curr_dummy RANGE 1 ${total_dummies}) + file(APPEND ${dummy_header} " res += dummy_for_${LIB_NAME}_${curr_dummy}();\n") + endforeach() + file(APPEND ${dummy_header} " return res;\n}\n\n} } // namespaces") + + # set the dummy header property so we don't recreate the dummy headers the next time this macro is called for this library + set_target_properties(${lib} PROPERTIES DOCTEST_DUMMY_HEADER ${dummy_header}) + set(DDH ${dummy_header}) + endif() + + get_target_property(DFLLTD ${target} DOCTEST_FORCE_LINKED_LIBRARIES_THROUGH_DUMMIES) + get_target_property(target_sources ${target} SOURCES) + + if("${DFLLTD}" STREQUAL "DFLLTD-NOTFOUND") + # if no library has been force linked to this target + foreach(src ${target_sources}) + if(${src} MATCHES \\.\(cc|cp|cpp|CPP|c\\+\\+|cxx\)$) + doctest_include_file_in_sources(${DDH} ${src}) + break() + endif() + endforeach() + + # add the library as force linked to this target + set_target_properties(${target} PROPERTIES DOCTEST_FORCE_LINKED_LIBRARIES_THROUGH_DUMMIES ${LIB_NAME}) + else() + # if this particular library hasn't been force linked to this target + list(FIND DFLLTD ${LIB_NAME} lib_forced_in_target) + if(${lib_forced_in_target} EQUAL -1) + foreach(src ${target_sources}) + if(${src} MATCHES \\.\(cc|cp|cpp|CPP|c\\+\\+|cxx\)$) + doctest_include_file_in_sources(${DDH} ${src}) + break() + endif() + endforeach() + + # add this library to the list of force linked libraries for this target + list(APPEND DFLLTD ${LIB_NAME}) + set_target_properties(${target} PROPERTIES DOCTEST_FORCE_LINKED_LIBRARIES_THROUGH_DUMMIES "${DFLLTD}") + else() + message(AUTHOR_WARNING "LIBRARY \"${lib}\" ALREADY FORCE-LINKED TO TARGET \"${target}\"!") + endif() + endif() +endfunction() diff --git a/examples/exe_with_static_libs/lib_1_src1.cpp b/examples/exe_with_static_libs/lib_1_src1.cpp new file mode 100644 index 0000000..0ce2690 --- /dev/null +++ b/examples/exe_with_static_libs/lib_1_src1.cpp @@ -0,0 +1,4 @@ +#include "doctest.h" +#include + +TEST_CASE("asd") { printf("hello from \n"); } diff --git a/examples/exe_with_static_libs/lib_1_src2.cpp b/examples/exe_with_static_libs/lib_1_src2.cpp new file mode 100644 index 0000000..13ed390 --- /dev/null +++ b/examples/exe_with_static_libs/lib_1_src2.cpp @@ -0,0 +1,4 @@ +#include "doctest.h" +#include + +TEST_CASE("asd") { printf("hello from \n"); } diff --git a/examples/exe_with_static_libs/lib_2_src.cpp b/examples/exe_with_static_libs/lib_2_src.cpp new file mode 100644 index 0000000..68c3dad --- /dev/null +++ b/examples/exe_with_static_libs/lib_2_src.cpp @@ -0,0 +1,4 @@ +#include "doctest.h" +#include + +TEST_CASE("asd") { printf("hello from \n"); } diff --git a/examples/exe_with_static_libs/main.cpp b/examples/exe_with_static_libs/main.cpp new file mode 100644 index 0000000..427d25f --- /dev/null +++ b/examples/exe_with_static_libs/main.cpp @@ -0,0 +1,4 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "doctest.h" + +TEST_CASE("main") { printf("hello from \n"); } diff --git a/examples/exe_with_static_libs/test_output/exe_with_static_libs.txt b/examples/exe_with_static_libs/test_output/exe_with_static_libs.txt new file mode 100644 index 0000000..fa25c1b --- /dev/null +++ b/examples/exe_with_static_libs/test_output/exe_with_static_libs.txt @@ -0,0 +1,9 @@ +[doctest] doctest version is "1.0.0" +[doctest] run with "--help" for options +hello from +hello from +hello from +hello from +=============================================================================== +[doctest] test cases: 4 | 4 passed | 0 failed | 0 skipped +[doctest] assertions: 0 | 0 passed | 0 failed | -- cgit v1.2.3