diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 0412c905a..3b634e6d9 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -84,6 +84,11 @@ cmExportBuildFileGenerator std::string prop = "IMPORTED_LOCATION"; prop += suffix; std::string value = target->GetFullPath(config, false); + if(target->IsAppBundleOnApple()) + { + value += ".app/Contents/MacOS/"; + value += target->GetFullName(config, false); + } properties[prop] = value; } diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index d2c8ccba7..6cf30c954 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -282,14 +282,19 @@ cmExportFileGenerator << " PROPERTY ENABLE_EXPORTS 1)\n"; } - // Mark the imported framework. This is done even on non-Apple - // platforms for reference and consistency purposes. - if(target->GetType() == cmTarget::SHARED_LIBRARY && - target->GetPropertyAsBool("FRAMEWORK")) + // Mark the imported library if it is a framework. + if(target->IsFrameworkOnApple()) { os << "SET_PROPERTY(TARGET " << targetName << " PROPERTY FRAMEWORK 1)\n"; } + + // Mark the imported executable if it is an application bundle. + if(target->IsAppBundleOnApple()) + { + os << "SET_PROPERTY(TARGET " << targetName + << " PROPERTY MACOSX_BUNDLE 1)\n"; + } os << "\n"; } diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index f378106e6..fe6cdb52b 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -160,8 +160,8 @@ cmExportInstallFileGenerator te->RuntimeGenerator, properties); this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator, properties); - - // TODO: Bundles? + this->SetImportLocationProperty(config, suffix, + te->BundleGenerator, properties); // If any file location was set for the target add it to the // import file. @@ -227,12 +227,17 @@ cmExportInstallFileGenerator std::string fname = itgen->GetInstallFilename(config); value += fname; - // Fix name for frameworks. + // Fix name for frameworks and bundles. if(itgen->GetTarget()->IsFrameworkOnApple()) { value += ".framework/"; value += fname; } + else if(itgen->GetTarget()->IsAppBundleOnApple()) + { + value += ".app/Contents/MacOS/"; + value += fname; + } // Store the property. properties[prop] = value; diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 863f138d3..056e2763e 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -451,9 +451,9 @@ bool cmInstallCommand::HandleTargetsMode(std::vector const& args) break; case cmTarget::EXECUTABLE: { - // Executables use the RUNTIME properties. - if(target.GetPropertyAsBool("MACOSX_BUNDLE")) + if(target.IsAppBundleOnApple()) { + // Application bundles use the BUNDLE properties. if (!bundleArgs.GetDestination().empty()) { bundleGenerator = CreateInstallTargetGenerator(target, bundleArgs, @@ -470,6 +470,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector const& args) } else { + // Executables use the RUNTIME properties. if (!runtimeArgs.GetDestination().empty()) { runtimeGenerator = CreateInstallTargetGenerator(target, diff --git a/Source/cmInstallCommand.h b/Source/cmInstallCommand.h index ed3a3a27a..e93c1f7fa 100644 --- a/Source/cmInstallCommand.h +++ b/Source/cmInstallCommand.h @@ -99,7 +99,7 @@ public: "\n" "The TARGETS signature:\n" " install(TARGETS targets... [EXPORT ]\n" - " [[ARCHIVE|LIBRARY|RUNTIME|FRAMEWORK]\n" + " [[ARCHIVE|LIBRARY|RUNTIME|FRAMEWORK|BUNDLE]\n" " [DESTINATION ]\n" " [PERMISSIONS permissions...]\n" " [CONFIGURATIONS [Debug|Release|...]]\n" @@ -107,10 +107,12 @@ public: " [OPTIONAL]\n" " ] [...])\n" "The TARGETS form specifies rules for installing targets from a " - "project. There are four kinds of target files that may be " - "installed: archive, library, runtime, and framework. " + "project. There are five kinds of target files that may be " + "installed: archive, library, runtime, framework, and bundle. " - "Executables are always treated as runtime targets. " + "Executables are treated as runtime targets, except that those " + "marked with the MACOSX_BUNDLE property are treated as bundle " + "targets on OS X. " "Static libraries are always treated as archive targets. " "Module libraries are always treated as library targets. " "For non-DLL platforms shared libraries are treated as library " diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index ae1628848..2cbb31ef8 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -176,8 +176,7 @@ cmInstallTargetGenerator from1 += targetName; // Handle OSX Bundles. - if(this->Target->GetMakefile()->IsOn("APPLE") && - this->Target->GetPropertyAsBool("MACOSX_BUNDLE")) + if(this->Target->IsAppBundleOnApple()) { // Compute the source locations of the bundle executable and // Info.plist file. diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 39b8a4e1b..5e37cede0 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -205,6 +205,8 @@ void cmTarget::DefineProperties(cmake *cm) "Full path to the main file on disk for an IMPORTED target.", "Specifies the location of an IMPORTED target file on disk. " "For executables this is the location of the executable file. " + "For bundles on OS X this is the location of the executable file " + "inside Contents/MacOS under the application bundle folder. " "For static libraries and modules this is the location of the " "library or module. " "For shared libraries on non-DLL platforms this is the location of " @@ -605,6 +607,14 @@ bool cmTarget::IsFrameworkOnApple() this->GetPropertyAsBool("FRAMEWORK")); } +//---------------------------------------------------------------------------- +bool cmTarget::IsAppBundleOnApple() +{ + return (this->GetType() == cmTarget::EXECUTABLE && + this->Makefile->IsOn("APPLE") && + this->GetPropertyAsBool("MACOSX_BUNDLE")); +} + //---------------------------------------------------------------------------- class cmTargetTraceDependencies { diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 45359bb3d..c1de1a3af 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -324,6 +324,9 @@ public: Apple. */ bool IsFrameworkOnApple(); + /** Return whether this target is an executable Bundle on Apple. */ + bool IsAppBundleOnApple(); + private: /** * A list of direct dependencies. Use in conjunction with DependencyMap. diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index ac2f10f12..24a3a56cd 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -21,14 +21,18 @@ add_library(testLib3 SHARED testLib3.c) add_library(testLib4 SHARED testLib4.c) set_property(TARGET testLib4 PROPERTY FRAMEWORK 1) +add_executable(testExe3 testExe3.c) +set_property(TARGET testExe3 PROPERTY MACOSX_BUNDLE 1) + # Install and export from install tree. install( - TARGETS testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 + TARGETS testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3 EXPORT exp RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib FRAMEWORK DESTINATION Frameworks + BUNDLE DESTINATION Applications ) install(EXPORT exp NAMESPACE exp_ DESTINATION lib/exp) @@ -37,7 +41,7 @@ export(TARGETS testExe1 testLib1 testLib2 NAMESPACE bld_ FILE ExportBuildTree.cmake ) -export(TARGETS testExe2 testLib3 testLib4 +export(TARGETS testExe2 testLib3 testLib4 testExe3 NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake ) diff --git a/Tests/ExportImport/Export/testExe3.c b/Tests/ExportImport/Export/testExe3.c new file mode 100644 index 000000000..895e2fc2d --- /dev/null +++ b/Tests/ExportImport/Export/testExe3.c @@ -0,0 +1,24 @@ +#include + +int main(int argc, const char* argv[]) +{ + if(argc < 2) + { + fprintf(stderr, "Must specify output file.\n"); + return 1; + } + { + FILE* f = fopen(argv[1], "w"); + if(f) + { + fprintf(f, "int generated_by_testExe3() { return 0; }\n"); + fclose(f); + } + else + { + fprintf(stderr, "Error writing to %s\n", argv[1]); + return 1; + } + } + return 0; +} diff --git a/Tests/ExportImport/Import/CMakeLists.txt b/Tests/ExportImport/Import/CMakeLists.txt index e6be1a828..b54a0692e 100644 --- a/Tests/ExportImport/Import/CMakeLists.txt +++ b/Tests/ExportImport/Import/CMakeLists.txt @@ -17,10 +17,16 @@ add_custom_command( COMMAND exp_testExe1 ${Import_BINARY_DIR}/exp_generated.c DEPENDS exp_testExe1 ) +add_custom_command( + OUTPUT ${Import_BINARY_DIR}/exp_generated3.c + COMMAND exp_testExe3 ${Import_BINARY_DIR}/exp_generated3.c + DEPENDS exp_testExe3 + ) add_executable(imp_testExe1 imp_testExe1.c ${Import_BINARY_DIR}/exp_generated.c + ${Import_BINARY_DIR}/exp_generated3.c ) # Try linking to a library imported from the install tree. @@ -36,10 +42,16 @@ add_custom_command( COMMAND bld_testExe1 ${Import_BINARY_DIR}/bld_generated.c DEPENDS bld_testExe1 ) +add_custom_command( + OUTPUT ${Import_BINARY_DIR}/bld_generated3.c + COMMAND bld_testExe3 ${Import_BINARY_DIR}/bld_generated3.c + DEPENDS bld_testExe3 + ) add_executable(imp_testExe1b imp_testExe1.c ${Import_BINARY_DIR}/bld_generated.c + ${Import_BINARY_DIR}/bld_generated3.c ) # Try linking to a library imported from the build tree. diff --git a/Tests/ExportImport/Import/imp_testExe1.c b/Tests/ExportImport/Import/imp_testExe1.c index 52ad8ff2d..0fbb689ff 100644 --- a/Tests/ExportImport/Import/imp_testExe1.c +++ b/Tests/ExportImport/Import/imp_testExe1.c @@ -1,9 +1,11 @@ extern int generated_by_testExe1(); +extern int generated_by_testExe3(); extern int testLib2(); extern int testLib3(); extern int testLib4(); int main() { - return testLib2() + generated_by_testExe1() + testLib3() + testLib4(); + return (testLib2() + generated_by_testExe1() + testLib3() + testLib4() + + generated_by_testExe3()); }