From d05e98f8d77e03c0c68ae3d7b5e5617f54dc6b07 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 8 Apr 2009 16:29:04 -0400 Subject: [PATCH] ENH: Allow IMPORTED_IMPLIB w/o IMPORTED_LOCATION Linking to a Windows shared library (.dll) requires only its import library (.lib). This teaches CMake to recognize SHARED IMPORTED library targets that set only IMPORTED_IMPLIB and not IMPORTED_LOCATION. --- Source/cmTarget.cxx | 91 ++++++++++++++++------ Tests/ExportImport/Export/CMakeLists.txt | 16 +++- Tests/ExportImport/Export/testLib5.c | 7 ++ Tests/ExportImport/Import/A/CMakeLists.txt | 14 +++- Tests/ExportImport/Import/A/imp_testExe1.c | 2 + 5 files changed, 104 insertions(+), 26 deletions(-) create mode 100644 Tests/ExportImport/Export/testLib5.c diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 09f261d75..8c8352fd1 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -2527,23 +2527,17 @@ std::string cmTarget::NormalGetFullPath(const char* config, bool implib, //---------------------------------------------------------------------------- std::string cmTarget::ImportedGetFullPath(const char* config, bool implib) { + std::string result; if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) { - if(implib) - { - return info->ImportLibrary; - } - else - { - return info->Location; - } + result = implib? info->ImportLibrary : info->Location; } - else + if(result.empty()) { - std::string result = this->GetName(); + result = this->GetName(); result += "-NOTFOUND"; - return result; } + return result; } //---------------------------------------------------------------------------- @@ -3467,7 +3461,7 @@ cmTarget::GetImportInfo(const char* config) // If the location is empty then the target is not available for // this configuration. - if(i->second.Location.empty()) + if(i->second.Location.empty() && i->second.ImportLibrary.empty()) { return 0; } @@ -3491,6 +3485,12 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, std::string suffix = "_"; suffix += desired_config; + // On a DLL platform there may be only IMPORTED_IMPLIB for a shared + // library or an executable with exports. + bool allowImp = + this->DLLPlatform && (this->GetType() == cmTarget::SHARED_LIBRARY || + this->IsExecutableWithExports()); + // Look for a mapping from the current project's configuration to // the imported project's configuration. std::vector mappedConfigs; @@ -3505,17 +3505,24 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, // If a mapping was found, check its configurations. const char* loc = 0; + const char* imp = 0; for(std::vector::const_iterator mci = mappedConfigs.begin(); - !loc && mci != mappedConfigs.end(); ++mci) + !loc && !imp && mci != mappedConfigs.end(); ++mci) { // Look for this configuration. std::string mcUpper = cmSystemTools::UpperCase(mci->c_str()); std::string locProp = "IMPORTED_LOCATION_"; locProp += mcUpper; loc = this->GetProperty(locProp.c_str()); + if(allowImp) + { + std::string impProp = "IMPORTED_IMPLIB_"; + impProp += mcUpper; + imp = this->GetProperty(impProp.c_str()); + } // If it was found, use it for all properties below. - if(loc) + if(loc || imp) { suffix = "_"; suffix += mcUpper; @@ -3525,23 +3532,29 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, // If we needed to find one of the mapped configurations but did not // then the target is not found. The project does not want any // other configuration. - if(!mappedConfigs.empty() && !loc) + if(!mappedConfigs.empty() && !loc && !imp) { return; } // If we have not yet found it then there are no mapped // configurations. Look for an exact-match. - if(!loc) + if(!loc && !imp) { std::string locProp = "IMPORTED_LOCATION"; locProp += suffix; loc = this->GetProperty(locProp.c_str()); + if(allowImp) + { + std::string impProp = "IMPORTED_IMPLIB"; + impProp += suffix; + imp = this->GetProperty(impProp.c_str()); + } } // If we have not yet found it then there are no mapped // configurations and no exact match. - if(!loc) + if(!loc && !imp) { // The suffix computed above is not useful. suffix = ""; @@ -3549,11 +3562,15 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, // Look for a configuration-less location. This may be set by // manually-written code. loc = this->GetProperty("IMPORTED_LOCATION"); + if(allowImp) + { + imp = this->GetProperty("IMPORTED_IMPLIB"); + } } // If we have not yet found it then the project is willing to try // any available configuration. - if(!loc) + if(!loc && !imp) { std::vector availableConfigs; if(const char* iconfigs = this->GetProperty("IMPORTED_CONFIGURATIONS")) @@ -3562,25 +3579,49 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, } for(std::vector::const_iterator aci = availableConfigs.begin(); - !loc && aci != availableConfigs.end(); ++aci) + !loc && !imp && aci != availableConfigs.end(); ++aci) { suffix = "_"; suffix += cmSystemTools::UpperCase(*aci); std::string locProp = "IMPORTED_LOCATION"; locProp += suffix; loc = this->GetProperty(locProp.c_str()); + if(allowImp) + { + std::string impProp = "IMPORTED_IMPLIB"; + impProp += suffix; + imp = this->GetProperty(impProp.c_str()); + } } } // If we have not yet found it then the target is not available. - if(!loc) + if(!loc && !imp) { return; } // A provided configuration has been chosen. Load the // configuration's properties. - info.Location = loc; + + // Get the location. + if(loc) + { + info.Location = loc; + } + else + { + std::string impProp = "IMPORTED_LOCATION"; + impProp += suffix; + if(const char* config_location = this->GetProperty(impProp.c_str())) + { + info.Location = config_location; + } + else if(const char* location = this->GetProperty("IMPORTED_LOCATION")) + { + info.Location = location; + } + } // Get the soname. if(this->GetType() == cmTarget::SHARED_LIBRARY) @@ -3613,8 +3654,12 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, } // Get the import library. - if(this->GetType() == cmTarget::SHARED_LIBRARY || - this->IsExecutableWithExports()) + if(imp) + { + info.ImportLibrary = imp; + } + else if(this->GetType() == cmTarget::SHARED_LIBRARY || + this->IsExecutableWithExports()) { std::string impProp = "IMPORTED_IMPLIB"; impProp += suffix; diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index 26687b1c3..19cd22f72 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -39,6 +39,8 @@ set_property(TARGET testLib3 PROPERTY SOVERSION 3) add_library(testLib4 SHARED testLib4.c) set_property(TARGET testLib4 PROPERTY FRAMEWORK 1) +add_library(testLib5 SHARED testLib5.c) + # Work-around: Visual Studio 6 does not support per-target object files. set(VS6) if("${CMAKE_GENERATOR}" MATCHES "Visual Studio 6") @@ -85,15 +87,27 @@ install( LIBRARY DESTINATION lib/impl ARCHIVE DESTINATION lib/impl ) +install( + TARGETS testLib5 + EXPORT exp + # Leave out RUNTIME DESTINATION to test implib-only export. + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + ) install(EXPORT exp NAMESPACE exp_ DESTINATION lib/exp) +# Install testLib5.dll outside the export. +if(WIN32) + install(TARGETS testLib5 RUNTIME DESTINATION bin) +endif(WIN32) + # Export from build tree. export(TARGETS testExe1 testLib1 testLib2 testLib3 testExe2libImp testLib3Imp NAMESPACE bld_ FILE ExportBuildTree.cmake ) -export(TARGETS testExe2 testLib4 testExe3 testExe2lib +export(TARGETS testExe2 testLib4 testLib5 testExe3 testExe2lib testLib4lib testLib4libdbg testLib4libopt NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake diff --git a/Tests/ExportImport/Export/testLib5.c b/Tests/ExportImport/Export/testLib5.c new file mode 100644 index 000000000..20a821513 --- /dev/null +++ b/Tests/ExportImport/Export/testLib5.c @@ -0,0 +1,7 @@ +#if defined(_WIN32) || defined(__CYGWIN__) +# define testLib5_EXPORT __declspec(dllexport) +#else +# define testLib5_EXPORT +#endif + +testLib5_EXPORT int testLib5(void) { return 0; } diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt index 16cff2df2..e874cdb28 100644 --- a/Tests/ExportImport/Import/A/CMakeLists.txt +++ b/Tests/ExportImport/Import/A/CMakeLists.txt @@ -23,7 +23,12 @@ add_executable(imp_testExe1 ) # Try linking to a library imported from the install tree. -target_link_libraries(imp_testExe1 exp_testLib2 exp_testLib3 exp_testLib4) +target_link_libraries(imp_testExe1 + exp_testLib2 + exp_testLib3 + exp_testLib4 + exp_testLib5 + ) # Try building a plugin to an executable imported from the install tree. add_library(imp_mod1 MODULE imp_mod1.c) @@ -48,7 +53,12 @@ add_executable(imp_testExe1b ) # Try linking to a library imported from the build tree. -target_link_libraries(imp_testExe1b bld_testLib2 bld_testLib3 bld_testLib4) +target_link_libraries(imp_testExe1b + bld_testLib2 + bld_testLib3 + bld_testLib4 + bld_testLib5 + ) # Try building a plugin to an executable imported from the build tree. add_library(imp_mod1b MODULE imp_mod1.c) diff --git a/Tests/ExportImport/Import/A/imp_testExe1.c b/Tests/ExportImport/Import/A/imp_testExe1.c index 6424d3399..6a6ba0fbe 100644 --- a/Tests/ExportImport/Import/A/imp_testExe1.c +++ b/Tests/ExportImport/Import/A/imp_testExe1.c @@ -4,6 +4,7 @@ extern int testLib2(); extern int testLib3(); extern int testLib4(); extern int testLib4lib(); +extern int testLib5(); /* Switch a symbol between debug and optimized builds to make sure the proper library is found from the testLib4 link interface. */ @@ -17,5 +18,6 @@ extern testLib4libcfg(void); int main() { return (testLib2() + generated_by_testExe1() + testLib3() + testLib4() + + testLib5() + generated_by_testExe3() + testLib4lib() + testLib4libcfg()); }