diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 8627cf2820..516720535d 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -423,14 +423,12 @@ void cmGlobalXCodeGenerator::AddExtraTargets( // Add XCODE depend helper std::string dir = root->GetCurrentBinaryDirectory(); cmCustomCommandLine makeHelper; - if (this->XcodeVersion < 50) { - makeHelper.push_back("make"); - makeHelper.push_back("-C"); - makeHelper.push_back(dir); - makeHelper.push_back("-f"); - makeHelper.push_back(this->CurrentXCodeHackMakefile); - makeHelper.push_back(""); // placeholder, see below - } + makeHelper.push_back("make"); + makeHelper.push_back("-C"); + makeHelper.push_back(dir); + makeHelper.push_back("-f"); + makeHelper.push_back(this->CurrentXCodeHackMakefile); + makeHelper.push_back(""); // placeholder, see below // Add ZERO_CHECK bool regenerate = !mf->IsOn("CMAKE_SUPPRESS_REGENERATION"); @@ -475,13 +473,12 @@ void cmGlobalXCodeGenerator::AddExtraTargets( // run the depend check makefile as a post build rule // this will make sure that when the next target is built // things are up-to-date - if (!makeHelper.empty() && - (target->GetType() == cmStateEnums::EXECUTABLE || - // Nope - no post-build for OBJECT_LIRBRARY - // target->GetType() == cmStateEnums::OBJECT_LIBRARY || - target->GetType() == cmStateEnums::STATIC_LIBRARY || - target->GetType() == cmStateEnums::SHARED_LIBRARY || - target->GetType() == cmStateEnums::MODULE_LIBRARY)) { + if (target->GetType() == cmStateEnums::OBJECT_LIBRARY || + (this->XcodeVersion < 50 && + (target->GetType() == cmStateEnums::EXECUTABLE || + target->GetType() == cmStateEnums::STATIC_LIBRARY || + target->GetType() == cmStateEnums::SHARED_LIBRARY || + target->GetType() == cmStateEnums::MODULE_LIBRARY))) { makeHelper[makeHelper.size() - 1] = // fill placeholder this->PostBuildMakeTarget(target->GetName(), "$(CONFIGURATION)"); cmCustomCommandLines commandLines; @@ -489,7 +486,8 @@ void cmGlobalXCodeGenerator::AddExtraTargets( std::vector no_byproducts; lg->GetMakefile()->AddCustomCommandToTarget( target->GetName(), no_byproducts, no_depends, commandLines, - cmTarget::POST_BUILD, "Depend check for xcode", dir.c_str()); + cmTarget::POST_BUILD, "Depend check for xcode", dir.c_str(), true, + false, "", false, cmMakefile::AcceptObjectLibraryCommands); } if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY && @@ -3129,10 +3127,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( cmXCodeObject* t = *i; this->AddDependAndLinkInformation(t); } - if (this->XcodeVersion < 50) { - // now create xcode depend hack makefile - this->CreateXCodeDependHackTarget(targets); - } + this->CreateXCodeDependHackTarget(targets); // now add all targets to the root object cmXCodeObject* allTargets = this->CreateObject(cmXCodeObject::OBJECT_LIST); for (std::vector::iterator i = targets.begin(); @@ -3183,29 +3178,9 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( "default:\n" "\techo \"Do not invoke directly\"\n" "\n"; - makefileStream - << "# For each target create a dummy rule " - "so the target does not have to exist\n"; /* clang-format on */ - std::set emitted; - for (std::vector::iterator i = targets.begin(); - i != targets.end(); ++i) { - cmXCodeObject* target = *i; - std::map const& deplibs = - target->GetDependLibraries(); - for (std::map::const_iterator ci = - deplibs.begin(); - ci != deplibs.end(); ++ci) { - for (cmXCodeObject::StringVec::const_iterator d = ci->second.begin(); - d != ci->second.end(); ++d) { - if (emitted.insert(*d).second) { - makefileStream << this->ConvertToRelativeForMake(d->c_str()) - << ":\n"; - } - } - } - } - makefileStream << "\n\n"; + + std::set dummyRules; // Write rules to help Xcode relink things at the right time. /* clang-format off */ @@ -3224,8 +3199,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( cmGeneratorTarget* gt = target->GetTarget(); if (gt->GetType() == cmStateEnums::EXECUTABLE || - // Nope - no post-build for OBJECT_LIRBRARY - // gt->GetType() == cmStateEnums::OBJECT_LIBRARY || + gt->GetType() == cmStateEnums::OBJECT_LIBRARY || gt->GetType() == cmStateEnums::STATIC_LIBRARY || gt->GetType() == cmStateEnums::SHARED_LIBRARY || gt->GetType() == cmStateEnums::MODULE_LIBRARY) { @@ -3235,6 +3209,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( } if (gt->GetType() == cmStateEnums::EXECUTABLE || + gt->GetType() == cmStateEnums::STATIC_LIBRARY || gt->GetType() == cmStateEnums::SHARED_LIBRARY || gt->GetType() == cmStateEnums::MODULE_LIBRARY) { std::string tfull = gt->GetFullPath(configName); @@ -3252,6 +3227,15 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( } } + std::vector objlibs; + gt->GetObjectLibrariesCMP0026(objlibs); + for (std::vector::const_iterator it = + objlibs.begin(); + it != objlibs.end(); ++it) { + makefileStream << this->PostBuildMakeTarget((*it)->GetName(), *ct) + << ": " << trel << "\n"; + } + // Create a rule for this target. makefileStream << trel << ":"; @@ -3262,10 +3246,28 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( std::vector const& deplibs = x->second; for (std::vector::const_iterator d = deplibs.begin(); d != deplibs.end(); ++d) { - makefileStream << "\\\n\t" - << this->ConvertToRelativeForMake(d->c_str()); + std::string file = this->ConvertToRelativeForMake(d->c_str()); + makefileStream << "\\\n\t" << file; + dummyRules.insert(file); } } + + for (std::vector::const_iterator it = + objlibs.begin(); + it != objlibs.end(); ++it) { + + const std::string objLibName = (*it)->GetName(); + std::string d = this->GetObjectsNormalDirectory(this->CurrentProject, + configName, *it); + d += "lib"; + d += objLibName; + d += ".a"; + + std::string dependency = this->ConvertToRelativeForMake(d.c_str()); + makefileStream << "\\\n\t" << dependency; + dummyRules.insert(dependency); + } + // Write the action to remove the target if it is out of date. makefileStream << "\n"; makefileStream << "\t/bin/rm -f " @@ -3293,6 +3295,14 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( } } } + + makefileStream << "\n\n" + << "# For each target create a dummy rule" + << "so the target does not have to exist\n"; + for (std::set::const_iterator it = dummyRules.begin(); + it != dummyRules.end(); ++it) { + makefileStream << *it << ":\n"; + } } void cmGlobalXCodeGenerator::OutputXCodeProject( diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index b3d7a04301..c75d101ddc 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -684,7 +684,8 @@ void cmMakefile::AddCustomCommandToTarget( const std::vector& depends, const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type, const char* comment, const char* workingDir, bool escapeOldStyle, - bool uses_terminal, const std::string& depfile, bool command_expand_lists) + bool uses_terminal, const std::string& depfile, bool command_expand_lists, + ObjectLibraryCommands objLibraryCommands) { // Find the target to which to add the custom command. cmTargets::iterator ti = this->Targets.find(target); @@ -724,7 +725,8 @@ void cmMakefile::AddCustomCommandToTarget( return; } - if (ti->second.GetType() == cmStateEnums::OBJECT_LIBRARY) { + if (objLibraryCommands == RejectObjectLibraryCommands && + ti->second.GetType() == cmStateEnums::OBJECT_LIBRARY) { std::ostringstream e; e << "Target \"" << target << "\" is an OBJECT library " diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 9d9e90a76f..4d5ce98842 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -119,6 +119,13 @@ public: */ void FinalPass(); + /** How to handle custom commands for object libraries */ + enum ObjectLibraryCommands + { + RejectObjectLibraryCommands, + AcceptObjectLibraryCommands + }; + /** Add a custom command to the build. */ void AddCustomCommandToTarget( const std::string& target, const std::vector& byproducts, @@ -126,7 +133,8 @@ public: const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type, const char* comment, const char* workingDir, bool escapeOldStyle = true, bool uses_terminal = false, const std::string& depfile = "", - bool command_expand_lists = false); + bool command_expand_lists = false, + ObjectLibraryCommands objLibraryCommands = RejectObjectLibraryCommands); cmSourceFile* AddCustomCommandToOutput( const std::vector& outputs, const std::vector& byproducts, diff --git a/Tests/RunCMake/ObjectLibrary/Dependencies.cmake b/Tests/RunCMake/ObjectLibrary/Dependencies.cmake new file mode 100644 index 0000000000..4e3db5f47b --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/Dependencies.cmake @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.7) + +project(Dependencies) + +add_library(myobj OBJECT ${CMAKE_BINARY_DIR}/depends_obj.cpp) +add_library(mylib STATIC $ depends_lib.cpp) +add_executable(myexe depends_main.cpp) +target_link_libraries(myexe mylib) + +enable_testing() +add_test(NAME myexe COMMAND $) diff --git a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake index 42973f8af2..9291218515 100644 --- a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake +++ b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake @@ -16,3 +16,22 @@ run_cmake(ObjWithObj) run_cmake(PostBuild) run_cmake(PreBuild) run_cmake(PreLink) + +function(run_Dependencies) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Dependencies-build) + set(RunCMake_TEST_NO_CLEAN 1) + + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + + run_cmake_command(Dependencies-build ${CMAKE_COMMAND} -E copy ${RunCMake_SOURCE_DIR}/depends_obj1.cpp ${RunCMake_TEST_BINARY_DIR}/depends_obj.cpp) + run_cmake(Dependencies) + run_cmake_command(Dependencies-build ${CMAKE_COMMAND} --build .) + run_cmake_command(Dependencies-build ${CMAKE_COMMAND} -E copy ${RunCMake_SOURCE_DIR}/depends_obj0.cpp ${RunCMake_TEST_BINARY_DIR}/depends_obj.cpp) + run_cmake_command(Dependencies-build ${CMAKE_COMMAND} -E sleep 1) + run_cmake_command(Dependencies-build ${CMAKE_COMMAND} -E touch_nocreate ${RunCMake_TEST_BINARY_DIR}/depends_obj.cpp) + run_cmake_command(Dependencies-build ${CMAKE_COMMAND} --build .) + run_cmake_command(Dependencies-build ${CMAKE_CTEST_COMMAND} -C Debug) +endfunction() + +run_Dependencies() diff --git a/Tests/RunCMake/ObjectLibrary/depends_lib.cpp b/Tests/RunCMake/ObjectLibrary/depends_lib.cpp new file mode 100644 index 0000000000..540b536291 --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/depends_lib.cpp @@ -0,0 +1,7 @@ +#include +int myobj_foo(); + +void mylib_foo() +{ + exit(myobj_foo()); +} diff --git a/Tests/RunCMake/ObjectLibrary/depends_main.cpp b/Tests/RunCMake/ObjectLibrary/depends_main.cpp new file mode 100644 index 0000000000..a9d323da2e --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/depends_main.cpp @@ -0,0 +1,7 @@ +void mylib_foo(); + +int main() +{ + mylib_foo(); + return 0; +} diff --git a/Tests/RunCMake/ObjectLibrary/depends_obj0.cpp b/Tests/RunCMake/ObjectLibrary/depends_obj0.cpp new file mode 100644 index 0000000000..73a17e7b7e --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/depends_obj0.cpp @@ -0,0 +1,4 @@ +int myobj_foo() +{ + return 0; +} diff --git a/Tests/RunCMake/ObjectLibrary/depends_obj1.cpp b/Tests/RunCMake/ObjectLibrary/depends_obj1.cpp new file mode 100644 index 0000000000..f62ef700d9 --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/depends_obj1.cpp @@ -0,0 +1,4 @@ +int myobj_foo() +{ + return 1; +}