From ed9763136acdb8594e4b85ab7b2e4e2828d8b775 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 26 Oct 2012 08:25:36 -0400 Subject: [PATCH 1/2] Optionally skip link dependencies on shared library files Add target property LINK_DEPENDS_NO_SHARED and initialization variable CMAKE_LINK_DEPENDS_NO_SHARED to enable this behavior. Suggested-by: Leif Walsh --- Source/cmComputeLinkInformation.cxx | 10 +++++++++- Source/cmComputeLinkInformation.h | 1 + Source/cmDocumentVariables.cxx | 9 +++++++++ Source/cmTarget.cxx | 17 +++++++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index cd3ef59a9..d8ffb5e83 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -277,6 +277,10 @@ cmComputeLinkInformation this->UseImportLibrary = this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")?true:false; + // Check whether we should skip dependencies on shared library files. + this->LinkDependsNoShared = + this->Target->GetPropertyAsBool("LINK_DEPENDS_NO_SHARED"); + // On platforms without import libraries there may be a special flag // to use when creating a plugin (module) that obtains symbols from // the program that will load it. @@ -650,7 +654,11 @@ void cmComputeLinkInformation::AddItem(std::string const& item, cmTarget* tgt) // Pass the full path to the target file. std::string lib = tgt->GetFullPath(config, implib, true); - this->Depends.push_back(lib); + if(!this->LinkDependsNoShared || + tgt->GetType() != cmTarget::SHARED_LIBRARY) + { + this->Depends.push_back(lib); + } this->AddTargetItem(lib, tgt); this->AddLibraryRuntimeInfo(lib, tgt); diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index f60f8d325..e0078af2a 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -82,6 +82,7 @@ private: // Configuration information. const char* Config; const char* LinkLanguage; + bool LinkDependsNoShared; // Modes for dealing with dependent shared libraries. enum SharedDepMode diff --git a/Source/cmDocumentVariables.cxx b/Source/cmDocumentVariables.cxx index 8db0e8f53..55d70f862 100644 --- a/Source/cmDocumentVariables.cxx +++ b/Source/cmDocumentVariables.cxx @@ -1221,6 +1221,15 @@ void cmDocumentVariables::DefineVariables(cmake* cm) false, "Variables that Control the Build"); + cm->DefineProperty + ("CMAKE_LINK_DEPENDS_NO_SHARED", cmProperty::VARIABLE, + "Whether to skip link dependencies on shared library files.", + "This variable initializes the LINK_DEPENDS_NO_SHARED " + "property on targets when they are created. " + "See that target property for additional information.", + false, + "Variables that Control the Build"); + cm->DefineProperty ("CMAKE_AUTOMOC", cmProperty::VARIABLE, "Whether to handle moc automatically for Qt targets.", diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 423b350e6..9cfcb638f 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -650,6 +650,22 @@ void cmTarget::DefineProperties(cmake *cm) "It is intended to specify dependencies on \"linker scripts\" for " "custom Makefile link rules."); + cm->DefineProperty + ("LINK_DEPENDS_NO_SHARED", cmProperty::TARGET, + "Do not depend on linked shared library files.", + "Set this property to true to tell CMake generators not to add " + "file-level dependencies on the shared library files linked by " + "this target. " + "Modification to the shared libraries will not be sufficient to " + "re-link this target. " + "Logical target-level dependencies will not be affected so the " + "linked shared libraries will still be brought up to date before " + "this target is built." + "\n" + "This property is initialized by the value of the variable " + "CMAKE_LINK_DEPENDS_NO_SHARED if it is set when a target is " + "created."); + cm->DefineProperty ("LINK_INTERFACE_LIBRARIES", cmProperty::TARGET, "List public interface libraries for a shared library or executable.", @@ -1314,6 +1330,7 @@ void cmTarget::SetMakefile(cmMakefile* mf) this->SetPropertyDefault("OSX_ARCHITECTURES", 0); this->SetPropertyDefault("AUTOMOC", 0); this->SetPropertyDefault("AUTOMOC_MOC_OPTIONS", 0); + this->SetPropertyDefault("LINK_DEPENDS_NO_SHARED", 0); this->SetPropertyDefault("LINK_INTERFACE_LIBRARIES", 0); this->SetPropertyDefault("WIN32_EXECUTABLE", 0); this->SetPropertyDefault("MACOSX_BUNDLE", 0); From 306796e86206f2b6cf0bd3b66735f2e825c6bcbd Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 9 Nov 2012 09:26:51 -0500 Subject: [PATCH 2/2] Teach BuildDepends test to cover LINK_DEPENDS_NO_SHARED Build a shared library and an executable linking to it inside the inner test. Set LINK_DEPENDS_NO_SHARED on the executable. Add a custom target to compare the output file times. Verify that on the first build the executable is newer than the library. Then modify a library source file. Verify that on the second build the library is newer because the executable did not have a dependency to re-link. --- Tests/BuildDepends/CMakeLists.txt | 34 +++++++++++++++++++ Tests/BuildDepends/Project/CMakeLists.txt | 15 ++++++++ .../link_depends_no_shared_check.cmake | 7 ++++ .../Project/link_depends_no_shared_exe.c | 9 +++++ .../Project/link_depends_no_shared_lib.c | 8 +++++ 5 files changed, 73 insertions(+) create mode 100644 Tests/BuildDepends/Project/link_depends_no_shared_check.cmake create mode 100644 Tests/BuildDepends/Project/link_depends_no_shared_exe.c create mode 100644 Tests/BuildDepends/Project/link_depends_no_shared_lib.c diff --git a/Tests/BuildDepends/CMakeLists.txt b/Tests/BuildDepends/CMakeLists.txt index 2a70b6eae..27927512a 100644 --- a/Tests/BuildDepends/CMakeLists.txt +++ b/Tests/BuildDepends/CMakeLists.txt @@ -60,6 +60,12 @@ file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_macro_dir.hxx file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_macro_tgt.hxx "static const char* zot_macro_tgt = \"zot_macro_tgt\";\n") +file(WRITE ${BuildDepends_BINARY_DIR}/Project/link_depends_no_shared_lib.h + "#define link_depends_no_shared_lib_value 1\n") +file(WRITE ${BuildDepends_BINARY_DIR}/Project/link_depends_no_shared_exe.h + "#define link_depends_no_shared_exe_value 0\n") +set(link_depends_no_shared_check_txt ${BuildDepends_BINARY_DIR}/Project/link_depends_no_shared_check.txt) + help_xcode_depends() message("Building project first time") @@ -125,6 +131,19 @@ else() message(SEND_ERROR "Project did not initially build properly: ${out}") endif() +if(EXISTS "${link_depends_no_shared_check_txt}") + file(STRINGS "${link_depends_no_shared_check_txt}" link_depends_no_shared_check LIMIT_COUNT 1) + if("${link_depends_no_shared_check}" STREQUAL "1") + message(STATUS "link_depends_no_shared_exe is newer than link_depends_no_shared_lib as expected.") + else() + message(SEND_ERROR "Project did not initially build properly: " + "link_depends_no_shared_exe is older than link_depends_no_shared_lib.") + endif() +else() + message(SEND_ERROR "Project did not initially build properly: " + "Targets link_depends_no_shared_lib and link_depends_no_shared_exe not both built.") +endif() + message("Waiting 3 seconds...") # any additional argument will cause ${bar} to wait forever execute_process(COMMAND ${bar} -infinite TIMEOUT 3 OUTPUT_VARIABLE out) @@ -141,6 +160,9 @@ file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_macro_dir.hxx file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_macro_tgt.hxx "static const char* zot_macro_tgt = \"zot_macro_tgt changed\";\n") +file(WRITE ${BuildDepends_BINARY_DIR}/Project/link_depends_no_shared_lib.h + "#define link_depends_no_shared_lib_value 0\n") + if(TEST_LINK_DEPENDS) file(WRITE ${TEST_LINK_DEPENDS} "2") endif() @@ -219,3 +241,15 @@ is not newer than dependency ") endif() endif() + +if(EXISTS "${link_depends_no_shared_check_txt}") + file(STRINGS "${link_depends_no_shared_check_txt}" link_depends_no_shared_check LIMIT_COUNT 1) + if("${link_depends_no_shared_check}" STREQUAL "0") + message(STATUS "link_depends_no_shared_exe is older than link_depends_no_shared_lib as expected.") + else() + message(SEND_ERROR "Project did not rebuild properly: link_depends_no_shared_exe is newer than link_depends_no_shared_lib.") + endif() +else() + message(SEND_ERROR "Project did not rebuild properly. " + "Targets link_depends_no_shared_lib and link_depends_no_shared_exe not both built.") +endif() diff --git a/Tests/BuildDepends/Project/CMakeLists.txt b/Tests/BuildDepends/Project/CMakeLists.txt index 01f5f6267..f47335dda 100644 --- a/Tests/BuildDepends/Project/CMakeLists.txt +++ b/Tests/BuildDepends/Project/CMakeLists.txt @@ -107,3 +107,18 @@ if(TEST_LINK_DEPENDS) add_executable(linkdep linkdep.cxx) set_property(TARGET linkdep PROPERTY LINK_DEPENDS ${TEST_LINK_DEPENDS}) endif() + +add_library(link_depends_no_shared_lib SHARED link_depends_no_shared_lib.c + ${CMAKE_CURRENT_BINARY_DIR}/link_depends_no_shared_lib.h) +add_executable(link_depends_no_shared_exe link_depends_no_shared_exe.c + ${CMAKE_CURRENT_BINARY_DIR}/link_depends_no_shared_exe.h) +target_link_libraries(link_depends_no_shared_exe link_depends_no_shared_lib) +set_property(TARGET link_depends_no_shared_exe PROPERTY LINK_DEPENDS_NO_SHARED 1) +add_custom_target(link_depends_no_shared_check ALL + COMMAND ${CMAKE_COMMAND} + -Dlib=$ + -Dexe=$ + -Dout=${CMAKE_CURRENT_BINARY_DIR}/link_depends_no_shared_check.txt + -P ${CMAKE_CURRENT_SOURCE_DIR}/link_depends_no_shared_check.cmake + ) +add_dependencies(link_depends_no_shared_check link_depends_no_shared_exe) diff --git a/Tests/BuildDepends/Project/link_depends_no_shared_check.cmake b/Tests/BuildDepends/Project/link_depends_no_shared_check.cmake new file mode 100644 index 000000000..3a611370f --- /dev/null +++ b/Tests/BuildDepends/Project/link_depends_no_shared_check.cmake @@ -0,0 +1,7 @@ +if(NOT EXISTS "${lib}" OR NOT EXISTS "${exe}") + file(REMOVE "${out}") +elseif("${exe}" IS_NEWER_THAN "${lib}") + file(WRITE "${out}" "1\n") +else() + file(WRITE "${out}" "0\n") +endif() diff --git a/Tests/BuildDepends/Project/link_depends_no_shared_exe.c b/Tests/BuildDepends/Project/link_depends_no_shared_exe.c new file mode 100644 index 000000000..e9113a21d --- /dev/null +++ b/Tests/BuildDepends/Project/link_depends_no_shared_exe.c @@ -0,0 +1,9 @@ +#include "link_depends_no_shared_exe.h" +#ifdef _WIN32 +__declspec(dllimport) +#endif +int link_depends_no_shared_lib(void); +int main() +{ + return link_depends_no_shared_lib() + link_depends_no_shared_exe_value; +} diff --git a/Tests/BuildDepends/Project/link_depends_no_shared_lib.c b/Tests/BuildDepends/Project/link_depends_no_shared_lib.c new file mode 100644 index 000000000..d2262894b --- /dev/null +++ b/Tests/BuildDepends/Project/link_depends_no_shared_lib.c @@ -0,0 +1,8 @@ +#include "link_depends_no_shared_lib.h" +#ifdef _WIN32 +__declspec(dllexport) +#endif +int link_depends_no_shared_lib(void) +{ + return link_depends_no_shared_lib_value; +}