summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2019-04-15 14:52:11 (GMT)
committerKitware Robot <kwrobot@kitware.com>2019-04-15 14:52:21 (GMT)
commit0793464d95c3dbbe9ed87bb5882d29efb7a8e3c3 (patch)
tree54458011255823399eed7a0b76f5db980e8a4aa3
parente2128e11ac7ac38f33100f5277cb4ace8697bad8 (diff)
parent2bae6a1346cb95703a93dbf73c9689598c9056d1 (diff)
downloadCMake-0793464d95c3dbbe9ed87bb5882d29efb7a8e3c3.zip
CMake-0793464d95c3dbbe9ed87bb5882d29efb7a8e3c3.tar.gz
CMake-0793464d95c3dbbe9ed87bb5882d29efb7a8e3c3.tar.bz2
Merge topic 'ghs_custom'
2bae6a1346 GHS: Update tests and notes 3b415c60c1 GHS: Update ExternalProject for GHS tools 83c47ef5b8 GHS: Update project layout to accommodate gbuild inconsistencies 5d2e1404bd GHS: Update project layout to build targets correctly b6bfa7eeb2 GHS: Support add_dependencies() command 39ee9718d9 GHS: Support add_custom_target() command 8d3dad9a76 GHS: Support add_custom_command( OUTPUT ) signature 37acc9e229 GHS: Update custom command build events Acked-by: Kitware Robot <kwrobot@kitware.com> Acked-by: Narendhar Manimohan <narendhar15@gmail.com> Merge-request: !3119
-rw-r--r--Help/release/dev/ghs-custom-commands.rst5
-rw-r--r--Modules/ExternalProject.cmake38
-rw-r--r--Source/cmGhsMultiGpj.cxx4
-rw-r--r--Source/cmGhsMultiGpj.h3
-rw-r--r--Source/cmGhsMultiTargetGenerator.cxx449
-rw-r--r--Source/cmGhsMultiTargetGenerator.h25
-rw-r--r--Source/cmGlobalGhsMultiGenerator.cxx358
-rw-r--r--Source/cmGlobalGhsMultiGenerator.h69
-rw-r--r--Tests/CMakeLists.txt5
-rw-r--r--Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt110
-rw-r--r--Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt.in108
-rw-r--r--Tests/GhsMulti/GhsMultiCustomTarget/exe1.c5
-rw-r--r--Tests/GhsMulti/GhsMultiCustomTarget/lib1.c4
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/CMakeLists.txt12
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/exec/CMakeLists.txt11
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/exec/exe1.c8
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/lib/CMakeLists.txt17
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/lib/func1.c17
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/lib/lib1.h3
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/protolib/CMakeLists.txt28
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.c.in16
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.h.in7
-rw-r--r--Tests/GhsMulti/GhsMultiExternalProject/CMakeLists.txt14
-rw-r--r--Tests/GhsMulti/GhsMultiExternalProject/empty/CMakeLists.txt8
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt1
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt1
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt1
-rw-r--r--Tests/GhsMulti/GhsMultiPlatform/file1.c4
-rw-r--r--Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt6
-rw-r--r--Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt2
30 files changed, 1105 insertions, 234 deletions
diff --git a/Help/release/dev/ghs-custom-commands.rst b/Help/release/dev/ghs-custom-commands.rst
new file mode 100644
index 0000000..a29ef88
--- /dev/null
+++ b/Help/release/dev/ghs-custom-commands.rst
@@ -0,0 +1,5 @@
+ghs_custom_commands
+-------------------
+
+* The :generator:`Green Hills MULTI` generator now supports
+ :command:`add_custom_command` and :command:`add_custom_target`
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake
index 8f1e194..20b37d2 100644
--- a/Modules/ExternalProject.cmake
+++ b/Modules/ExternalProject.cmake
@@ -422,6 +422,10 @@ External Project Definition
different behavior depending on whether the build starts from a fresh
build directory or re-uses previous build contents.
+ If the CMake generator is the ``Green Hills MULTI`` and not overridden then
+ the orginal projects settings for the GHS toolset and target system
+ customization cache variables are propagated into the external project.
+
``SOURCE_SUBDIR <dir>``
When no ``CONFIGURE_COMMAND`` option is specified, the configure step
assumes the external project has a ``CMakeLists.txt`` file at the top of
@@ -2850,18 +2854,6 @@ function(_ep_extract_configure_command var name)
set(has_cmake_cache_default_args 1)
endif()
- if(has_cmake_cache_args OR has_cmake_cache_default_args)
- set(_ep_cache_args_script "<TMP_DIR>/${name}-cache-$<CONFIG>.cmake")
- if(has_cmake_cache_args)
- _ep_command_line_to_initial_cache(script_initial_cache_force "${cmake_cache_args}" 1)
- endif()
- if(has_cmake_cache_default_args)
- _ep_command_line_to_initial_cache(script_initial_cache_default "${cmake_cache_default_args}" 0)
- endif()
- _ep_write_initial_cache(${name} "${_ep_cache_args_script}" "${script_initial_cache_force}${script_initial_cache_default}")
- list(APPEND cmd "-C${_ep_cache_args_script}")
- endif()
-
get_target_property(cmake_generator ${name} _EP_CMAKE_GENERATOR)
get_target_property(cmake_generator_instance ${name} _EP_CMAKE_GENERATOR_INSTANCE)
get_target_property(cmake_generator_platform ${name} _EP_CMAKE_GENERATOR_PLATFORM)
@@ -2882,6 +2874,16 @@ function(_ep_extract_configure_command var name)
list(APPEND cmd "-G${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}")
else()
list(APPEND cmd "-G${CMAKE_GENERATOR}")
+ if("${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
+ set(has_cmake_cache_default_args 1)
+ set(cmake_cache_default_args ${cmake_cache_default_args}
+ "-DGHS_TARGET_PLATFORM:STRING=${GHS_TARGET_PLATFORM}"
+ "-DGHS_PRIMARY_TARGET:STRING=${GHS_PRIMARY_TARGET}"
+ "-DGHS_TOOLSET_ROOT:STRING=${GHS_TOOLSET_ROOT}"
+ "-DGHS_OS_ROOT:STRING=${GHS_OS_ROOT}"
+ "-DGHS_OS_DIR:STRING=${GHS_OS_DIR}"
+ "-DGHS_BSP_NAME:STRING=${GHS_BSP_NAME}")
+ endif()
endif()
if(cmake_generator_platform)
message(FATAL_ERROR "Option CMAKE_GENERATOR_PLATFORM not allowed without CMAKE_GENERATOR.")
@@ -2903,6 +2905,18 @@ function(_ep_extract_configure_command var name)
endif()
endif()
+ if(has_cmake_cache_args OR has_cmake_cache_default_args)
+ set(_ep_cache_args_script "<TMP_DIR>/${name}-cache-$<CONFIG>.cmake")
+ if(has_cmake_cache_args)
+ _ep_command_line_to_initial_cache(script_initial_cache_force "${cmake_cache_args}" 1)
+ endif()
+ if(has_cmake_cache_default_args)
+ _ep_command_line_to_initial_cache(script_initial_cache_default "${cmake_cache_default_args}" 0)
+ endif()
+ _ep_write_initial_cache(${name} "${_ep_cache_args_script}" "${script_initial_cache_force}${script_initial_cache_default}")
+ list(APPEND cmd "-C${_ep_cache_args_script}")
+ endif()
+
list(APPEND cmd "<SOURCE_DIR><SOURCE_SUBDIR>")
endif()
diff --git a/Source/cmGhsMultiGpj.cxx b/Source/cmGhsMultiGpj.cxx
index 8b69b51..da27971 100644
--- a/Source/cmGhsMultiGpj.cxx
+++ b/Source/cmGhsMultiGpj.cxx
@@ -9,7 +9,8 @@ static const char* GHS_TAG[] = { "[INTEGRITY Application]",
"[Project]",
"[Program]",
"[Reference]",
- "[Subproject]" };
+ "[Subproject]",
+ "[Custom Target]" };
const char* GhsMultiGpj::GetGpjTag(Types gpjType)
{
@@ -21,6 +22,7 @@ const char* GhsMultiGpj::GetGpjTag(Types gpjType)
case PROGRAM:
case REFERENCE:
case SUBPROJECT:
+ case CUSTOM_TARGET:
tag = GHS_TAG[gpjType];
break;
default:
diff --git a/Source/cmGhsMultiGpj.h b/Source/cmGhsMultiGpj.h
index 420eab1..e588150 100644
--- a/Source/cmGhsMultiGpj.h
+++ b/Source/cmGhsMultiGpj.h
@@ -16,7 +16,8 @@ public:
PROJECT,
PROGRAM,
REFERENCE,
- SUBPROJECT
+ SUBPROJECT,
+ CUSTOM_TARGET
};
static void WriteGpjTag(Types gpjType, std::ostream& fout);
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index 668bcbd..b80da72 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -3,7 +3,7 @@
#include "cmGhsMultiTargetGenerator.h"
#include "cmCustomCommand.h"
-#include "cmCustomCommandLines.h"
+#include "cmCustomCommandGenerator.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGhsMultiGenerator.h"
@@ -11,17 +11,17 @@
#include "cmLocalGenerator.h"
#include "cmLocalGhsMultiGenerator.h"
#include "cmMakefile.h"
+#include "cmOutputConverter.h"
#include "cmSourceFile.h"
+#include "cmSourceFileLocation.h"
#include "cmSourceGroup.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
-#include "cmTargetDepend.h"
#include <algorithm>
-#include <assert.h>
#include <ostream>
#include <set>
#include <utility>
@@ -32,6 +32,11 @@ cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target)
static_cast<cmLocalGhsMultiGenerator*>(target->GetLocalGenerator()))
, Makefile(target->Target->GetMakefile())
, Name(target->GetName())
+#ifdef _WIN32
+ , CmdWindowsShell(true)
+#else
+ , CmdWindowsShell(false)
+#endif
{
// Store the configuration name that is being used
if (const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) {
@@ -85,10 +90,19 @@ void cmGhsMultiTargetGenerator::Generate()
return;
}
case cmStateEnums::UTILITY: {
- std::string msg = "add_custom_target(<name> ...) not supported: ";
- msg += this->Name;
- cmSystemTools::Message(msg);
- return;
+ this->TargetNameReal = this->GeneratorTarget->GetName();
+ this->TagType = GhsMultiGpj::CUSTOM_TARGET;
+ break;
+ }
+ case cmStateEnums::GLOBAL_TARGET: {
+ this->TargetNameReal = this->GeneratorTarget->GetName();
+ if (this->TargetNameReal ==
+ this->GetGlobalGenerator()->GetInstallTargetName()) {
+ this->TagType = GhsMultiGpj::CUSTOM_TARGET;
+ } else {
+ return;
+ }
+ break;
}
default:
return;
@@ -105,29 +119,29 @@ void cmGhsMultiTargetGenerator::Generate()
void cmGhsMultiTargetGenerator::GenerateTarget()
{
- // Open the filestream in copy-if-different mode.
- std::string fname = this->LocalGenerator->GetCurrentBinaryDirectory();
- fname += "/";
- fname += this->Name;
- fname += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
- cmGeneratedFileStream fout(fname);
+ // Open the target file in copy-if-different mode.
+ std::string fproj = this->LocalGenerator->GetCurrentBinaryDirectory();
+ fproj += "/";
+ fproj += this->Name;
+ fproj += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
+ cmGeneratedFileStream fout(fproj);
fout.SetCopyIfDifferent(true);
this->GetGlobalGenerator()->WriteFileHeader(fout);
GhsMultiGpj::WriteGpjTag(this->TagType, fout);
- const std::string language(
- this->GeneratorTarget->GetLinkerLanguage(this->ConfigName));
-
- this->WriteTargetSpecifics(fout, this->ConfigName);
- this->SetCompilerFlags(this->ConfigName, language);
- this->WriteCompilerFlags(fout, this->ConfigName, language);
- this->WriteCompilerDefinitions(fout, this->ConfigName, language);
- this->WriteIncludes(fout, this->ConfigName, language);
- this->WriteTargetLinkLine(fout, this->ConfigName);
- this->WriteCustomCommands(fout);
+ if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
+ const std::string language(
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName));
+ this->WriteTargetSpecifics(fout, this->ConfigName);
+ this->SetCompilerFlags(this->ConfigName, language);
+ this->WriteCompilerFlags(fout, this->ConfigName, language);
+ this->WriteCompilerDefinitions(fout, this->ConfigName, language);
+ this->WriteIncludes(fout, this->ConfigName, language);
+ this->WriteTargetLinkLine(fout, this->ConfigName);
+ this->WriteBuildEvents(fout);
+ }
this->WriteSources(fout);
- this->WriteReferences(fout);
fout.Close();
}
@@ -304,47 +318,145 @@ void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout,
}
}
-void cmGhsMultiTargetGenerator::WriteCustomCommands(std::ostream& fout)
+void cmGhsMultiTargetGenerator::WriteBuildEvents(std::ostream& fout)
{
- WriteCustomCommandsHelper(fout, this->GeneratorTarget->GetPreBuildCommands(),
- cmTarget::PRE_BUILD);
- WriteCustomCommandsHelper(
- fout, this->GeneratorTarget->GetPostBuildCommands(), cmTarget::POST_BUILD);
+ this->WriteBuildEventsHelper(
+ fout, this->GeneratorTarget->GetPreBuildCommands(),
+ std::string("prebuild"), std::string("preexecShell"));
+
+ if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
+ this->WriteBuildEventsHelper(
+ fout, this->GeneratorTarget->GetPreLinkCommands(),
+ std::string("prelink"), std::string("preexecShell"));
+ }
+
+ this->WriteBuildEventsHelper(
+ fout, this->GeneratorTarget->GetPostBuildCommands(),
+ std::string("postbuild"), std::string("postexecShell"));
+}
+
+void cmGhsMultiTargetGenerator::WriteBuildEventsHelper(
+ std::ostream& fout, const std::vector<cmCustomCommand>& ccv,
+ std::string const& name, std::string const& cmd)
+{
+ int cmdcount = 0;
+
+ for (cmCustomCommand const& cc : ccv) {
+ cmCustomCommandGenerator ccg(cc, this->ConfigName, this->LocalGenerator);
+ // Open the filestream for this custom command
+ std::string fname = this->LocalGenerator->GetCurrentBinaryDirectory();
+ fname +=
+ "/" + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ fname += "/" + this->Name + "_" + name;
+ fname += std::to_string(cmdcount++);
+ fname += this->CmdWindowsShell ? ".bat" : ".sh";
+ cmGeneratedFileStream f(fname);
+ f.SetCopyIfDifferent(true);
+ this->WriteCustomCommandsHelper(f, ccg);
+ f.Close();
+ if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
+ fout << " :" << cmd << "=\"" << fname << "\"" << std::endl;
+ } else {
+ fout << fname << std::endl;
+ fout << " :outputName=\"" << fname << ".rule\"" << std::endl;
+ }
+ for (auto& byp : ccg.GetByproducts()) {
+ fout << " :extraOutputFile=\"" << byp << "\"" << std::endl;
+ }
+ }
}
void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
- std::ostream& fout, std::vector<cmCustomCommand> const& commandsSet,
- cmTarget::CustomCommandType const commandType)
+ std::ostream& fout, cmCustomCommandGenerator const& ccg)
{
- for (cmCustomCommand const& customCommand : commandsSet) {
- cmCustomCommandLines const& commandLines = customCommand.GetCommandLines();
- for (cmCustomCommandLine const& command : commandLines) {
- switch (commandType) {
- case cmTarget::PRE_BUILD:
- fout << " :preexecShellSafe=";
- break;
- case cmTarget::POST_BUILD:
- fout << " :postexecShellSafe=";
- break;
- default:
- assert("Only pre and post are supported");
+ std::vector<std::string> cmdLines;
+
+ // if the command specified a working directory use it.
+ std::string dir = this->LocalGenerator->GetCurrentBinaryDirectory();
+ std::string currentBinDir = dir;
+ std::string workingDir = ccg.GetWorkingDirectory();
+ if (!workingDir.empty()) {
+ dir = workingDir;
+ }
+
+ // Line to check for error between commands.
+#ifdef _WIN32
+ std::string check_error = "if %errorlevel% neq 0 exit /b %errorlevel%";
+#else
+ std::string check_error = "if [[ $? -ne 0 ]]; then exit 1; fi";
+#endif
+
+#ifdef _WIN32
+ cmdLines.push_back("@echo off");
+#endif
+ // Echo the custom command's comment text.
+ const char* comment = ccg.GetComment();
+ if (comment && *comment) {
+ std::string echocmd = "echo ";
+ echocmd += comment;
+ cmdLines.push_back(std::move(echocmd));
+ }
+
+ // Switch to working directory
+ std::string cdCmd;
+#ifdef _WIN32
+ std::string cdStr = "cd /D ";
+#else
+ std::string cdStr = "cd ";
+#endif
+ cdCmd = cdStr +
+ this->LocalGenerator->ConvertToOutputFormat(dir, cmOutputConverter::SHELL);
+ cmdLines.push_back(std::move(cdCmd));
+
+ for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
+ // Build the command line in a single string.
+ std::string cmd = ccg.GetCommand(c);
+ if (!cmd.empty()) {
+ // Use "call " before any invocations of .bat or .cmd files
+ // invoked as custom commands in the WindowsShell.
+ //
+ bool useCall = false;
+
+ if (this->CmdWindowsShell) {
+ std::string suffix;
+ if (cmd.size() > 4) {
+ suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size() - 4));
+ if (suffix == ".bat" || suffix == ".cmd") {
+ useCall = true;
+ }
+ }
}
- bool firstIteration = true;
- for (std::string const& commandLine : command) {
- std::string subCommandE =
- this->LocalGenerator->EscapeForShell(commandLine, true);
- fout << (firstIteration ? "'" : " ");
- // Need to double escape backslashes
- cmSystemTools::ReplaceString(subCommandE, "\\", "\\\\");
- fout << subCommandE;
- firstIteration = false;
+ cmSystemTools::ReplaceString(cmd, "/./", "/");
+ // Convert the command to a relative path only if the current
+ // working directory will be the start-output directory.
+ bool had_slash = cmd.find('/') != std::string::npos;
+ if (workingDir.empty()) {
+ cmd =
+ this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir, cmd);
}
- if (!command.empty()) {
- fout << "'" << std::endl;
+ bool has_slash = cmd.find('/') != std::string::npos;
+ if (had_slash && !has_slash) {
+ // This command was specified as a path to a file in the
+ // current directory. Add a leading "./" so it can run
+ // without the current directory being in the search path.
+ cmd = "./" + cmd;
}
+ cmd = this->LocalGenerator->ConvertToOutputFormat(
+ cmd, cmOutputConverter::SHELL);
+ if (useCall) {
+ cmd = "call " + cmd;
+ }
+ ccg.AppendArguments(c, cmd);
+ cmdLines.push_back(std::move(cmd));
}
}
+
+ // push back the custom commands
+ for (auto const& c : cmdLines) {
+ fout << c << std::endl;
+ fout << check_error << std::endl;
+ }
}
void cmGhsMultiTargetGenerator::WriteSourceProperty(
@@ -385,7 +497,7 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
/* list of known groups and the order they are displayed in a project file */
const std::vector<std::string> standardGroups = {
- "Header Files", "Source Files", "CMake Rules",
+ "CMake Rules", "Header Files", "Source Files",
"Object Files", "Object Libraries", "Resources"
};
@@ -403,6 +515,14 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
groupFilesList[i] = *n;
i += 1;
groupNames.erase(gn);
+ } else if (this->TagType == GhsMultiGpj::CUSTOM_TARGET &&
+ gn == "CMake Rules") {
+ /* make sure that rules folder always exists in case of custom targets
+ * that have no custom commands except for pre or post build events.
+ */
+ groupFilesList.resize(groupFilesList.size() + 1);
+ groupFilesList[i] = gn;
+ i += 1;
}
}
@@ -433,7 +553,7 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
/* write files into the proper project file
* -- groups go into main project file
- * unless FOLDER property or variable is set.
+ * unless NO_SOURCE_GROUP_FILE property or variable is set.
*/
for (auto& sg : groupFilesList) {
std::ostream* fout;
@@ -472,33 +592,98 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
} else {
*fout << "{comment} " << sg << std::endl;
}
+ } else if (sg.empty()) {
+ *fout << "{comment} Others" << std::endl;
}
- /* output rule for each source file */
- for (const cmSourceFile* si : groupFiles[sg]) {
-
- // Convert filename to native system
- // WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on
- // windows when opening some files from the search window.
- std::string fname(si->GetFullPath());
- cmSystemTools::ConvertToOutputSlashes(fname);
- *fout << fname << std::endl;
-
- if ("ld" != si->GetExtension() && "int" != si->GetExtension() &&
- "bsp" != si->GetExtension()) {
- WriteObjectLangOverride(*fout, si);
+ if (sg != "CMake Rules") {
+ /* output rule for each source file */
+ for (const cmSourceFile* si : groupFiles[sg]) {
+ bool compile = true;
+ // Convert filename to native system
+ // WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on
+ // windows when opening some files from the search window.
+ std::string fname(si->GetFullPath());
+ cmSystemTools::ConvertToOutputSlashes(fname);
+
+ /* For custom targets list any associated sources,
+ * comment out source code to prevent it from being
+ * compiled when processing this target.
+ * Otherwise, comment out any custom command (main) dependencies that
+ * are listed as source files to prevent them from being considered
+ * part of the build.
+ */
+ std::string comment;
+ if ((this->TagType == GhsMultiGpj::CUSTOM_TARGET &&
+ !si->GetLanguage().empty()) ||
+ si->GetCustomCommand()) {
+ comment = "{comment} ";
+ compile = false;
+ }
+
+ *fout << comment << fname << std::endl;
+ if (compile) {
+ if ("ld" != si->GetExtension() && "int" != si->GetExtension() &&
+ "bsp" != si->GetExtension()) {
+ WriteObjectLangOverride(*fout, si);
+ }
+
+ this->WriteSourceProperty(*fout, si, "INCLUDE_DIRECTORIES", "-I");
+ this->WriteSourceProperty(*fout, si, "COMPILE_DEFINITIONS", "-D");
+ this->WriteSourceProperty(*fout, si, "COMPILE_OPTIONS", "");
+
+ /* to avoid clutter in the GUI only print out the objectName if it
+ * has been renamed */
+ std::string objectName = this->GeneratorTarget->GetObjectName(si);
+ if (!objectName.empty() &&
+ this->GeneratorTarget->HasExplicitObjectName(si)) {
+ *fout << " -o " << objectName << std::endl;
+ }
+ }
}
-
- this->WriteSourceProperty(*fout, si, "INCLUDE_DIRECTORIES", "-I");
- this->WriteSourceProperty(*fout, si, "COMPILE_DEFINITIONS", "-D");
- this->WriteSourceProperty(*fout, si, "COMPILE_OPTIONS", "");
-
- /* to avoid clutter in the gui only print out the objectName if it has
- * been renamed */
- std::string objectName = this->GeneratorTarget->GetObjectName(si);
- if (!objectName.empty() &&
- this->GeneratorTarget->HasExplicitObjectName(si)) {
- *fout << " -o " << objectName << std::endl;
+ } else {
+ std::vector<cmSourceFile const*> customCommands;
+ if (ComputeCustomCommandOrder(customCommands)) {
+ std::string message = "The custom commands for target [" +
+ this->GeneratorTarget->GetName() + "] had a cycle.\n";
+ cmSystemTools::Error(message);
+ } else {
+ /* Custom targets do not have a dependency on SOURCES files.
+ * Therefore the dependency list may include SOURCES files after the
+ * custom target. Because nothing can depend on the custom target just
+ * move it to the last item.
+ */
+ for (auto sf = customCommands.begin(); sf != customCommands.end();
+ ++sf) {
+ if (((*sf)->GetLocation()).GetName() == this->Name + ".rule") {
+ std::rotate(sf, sf + 1, customCommands.end());
+ break;
+ }
+ }
+ int cmdcount = 0;
+ for (auto& sf : customCommands) {
+ const cmCustomCommand* cc = sf->GetCustomCommand();
+ cmCustomCommandGenerator ccg(*cc, this->ConfigName,
+ this->LocalGenerator);
+
+ // Open the filestream for this custom command
+ std::string fname =
+ this->LocalGenerator->GetCurrentBinaryDirectory();
+ fname += "/" +
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ fname += "/" + this->Name + "_cc";
+ fname += std::to_string(cmdcount++) + "_";
+ fname += (sf->GetLocation()).GetName();
+ fname += this->CmdWindowsShell ? ".bat" : ".sh";
+ cmGeneratedFileStream f(fname);
+ f.SetCopyIfDifferent(true);
+ this->WriteCustomCommandsHelper(f, ccg);
+ f.Close();
+ this->WriteCustomCommandLine(*fout, fname, ccg);
+ }
+ }
+ if (this->TagType == GhsMultiGpj::CUSTOM_TARGET) {
+ this->WriteBuildEvents(*fout);
}
}
}
@@ -508,6 +693,33 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
}
}
+void cmGhsMultiTargetGenerator::WriteCustomCommandLine(
+ std::ostream& fout, std::string& fname, cmCustomCommandGenerator const& ccg)
+{
+ /* NOTE: Customization Files are not well documented. Testing showed
+ * that ":outputName=file" can only be used once per script. The
+ * script will only run if ":outputName=file" is missing or just run
+ * once if ":outputName=file" is not specified. If there are
+ * multiple outputs then the script needs to be listed multiple times
+ * for each output. Otherwise it won't rerun the script if one of
+ * the outputs is manually deleted.
+ */
+ bool specifyExtra = true;
+ for (auto& out : ccg.GetOutputs()) {
+ fout << fname << std::endl;
+ fout << " :outputName=\"" << out << "\"" << std::endl;
+ if (specifyExtra) {
+ for (auto& byp : ccg.GetByproducts()) {
+ fout << " :extraOutputFile=\"" << byp << "\"" << std::endl;
+ }
+ for (auto& dep : ccg.GetDepends()) {
+ fout << " :depends=\"" << dep << "\"" << std::endl;
+ }
+ specifyExtra = false;
+ }
+ }
+}
+
void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
std::ostream& fout, const cmSourceFile* sourceFile)
{
@@ -521,35 +733,6 @@ void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
}
}
-void cmGhsMultiTargetGenerator::WriteReferences(std::ostream& fout)
-{
- // This only applies to INTEGRITY Applications
- if (this->TagType != GhsMultiGpj::INTERGRITY_APPLICATION) {
- return;
- }
-
- // Get the targets that this one depends upon
- cmTargetDependSet unordered =
- this->GetGlobalGenerator()->GetTargetDirectDepends(this->GeneratorTarget);
- cmGlobalGhsMultiGenerator::OrderedTargetDependSet ordered(unordered,
- this->Name);
- for (auto& t : ordered) {
- std::string tname = t->GetName();
- std::string tpath = t->LocalGenerator->GetCurrentBinaryDirectory();
- std::string rootpath = this->LocalGenerator->GetCurrentBinaryDirectory();
- std::string outpath =
- this->LocalGenerator->MaybeConvertToRelativePath(rootpath, tpath) + "/" +
- tname + "REF" + cmGlobalGhsMultiGenerator::FILE_EXTENSION;
-
- fout << outpath;
- fout << " ";
- GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fout);
-
- // Tell the global generator that a refernce project needs to be created
- t->Target->SetProperty("GHS_REFERENCE_PROJECT", "ON");
- }
-}
-
bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()
{
const char* p = this->GeneratorTarget->GetProperty("ghs_integrity_app");
@@ -566,3 +749,51 @@ bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()
}
return false;
}
+
+bool cmGhsMultiTargetGenerator::ComputeCustomCommandOrder(
+ std::vector<cmSourceFile const*>& order)
+{
+ std::set<cmSourceFile const*> temp;
+ std::set<cmSourceFile const*> perm;
+
+ // Collect all custom commands for this target
+ std::vector<cmSourceFile const*> customCommands;
+ this->GeneratorTarget->GetCustomCommands(customCommands, this->ConfigName);
+
+ for (cmSourceFile const* si : customCommands) {
+ bool r = VisitCustomCommand(temp, perm, order, si);
+ if (r) {
+ return r;
+ }
+ }
+ return false;
+}
+
+bool cmGhsMultiTargetGenerator::VisitCustomCommand(
+ std::set<cmSourceFile const*>& temp, std::set<cmSourceFile const*>& perm,
+ std::vector<cmSourceFile const*>& order, cmSourceFile const* si)
+{
+ /* check if permanent mark is set*/
+ if (perm.find(si) == perm.end()) {
+ /* set temporary mark; check if revisit*/
+ if (temp.insert(si).second) {
+ for (auto& di : si->GetCustomCommand()->GetDepends()) {
+ cmSourceFile const* sf = this->GeneratorTarget->GetLocalGenerator()
+ ->GetMakefile()
+ ->GetSourceFileWithOutput(di);
+ /* if sf exists then visit */
+ if (sf && this->VisitCustomCommand(temp, perm, order, sf)) {
+ return true;
+ }
+ }
+ /* mark as complete; insert into beginning of list*/
+ perm.insert(si);
+ order.push_back(si);
+ return false;
+ }
+ /* revisiting item - not a DAG */
+ return true;
+ }
+ /* already complete */
+ return false;
+}
diff --git a/Source/cmGhsMultiTargetGenerator.h b/Source/cmGhsMultiTargetGenerator.h
index a4e23d9..a131567 100644
--- a/Source/cmGhsMultiTargetGenerator.h
+++ b/Source/cmGhsMultiTargetGenerator.h
@@ -5,14 +5,14 @@
#include "cmGhsMultiGpj.h"
-#include "cmTarget.h"
-
#include <iosfwd>
#include <map>
+#include <set>
#include <string>
#include <vector>
class cmCustomCommand;
+class cmCustomCommandGenerator;
class cmGeneratorTarget;
class cmGlobalGhsMultiGenerator;
class cmLocalGhsMultiGenerator;
@@ -49,15 +49,23 @@ private:
void WriteIncludes(std::ostream& fout, const std::string& config,
const std::string& language);
void WriteTargetLinkLine(std::ostream& fout, std::string const& config);
- void WriteCustomCommands(std::ostream& fout);
- void WriteCustomCommandsHelper(
- std::ostream& fout, std::vector<cmCustomCommand> const& commandsSet,
- cmTarget::CustomCommandType commandType);
+ void WriteBuildEvents(std::ostream& fout);
+ void WriteBuildEventsHelper(std::ostream& fout,
+ const std::vector<cmCustomCommand>& ccv,
+ std::string const& name, std::string const& cmd);
+ void WriteCustomCommandsHelper(std::ostream& fout,
+ cmCustomCommandGenerator const& ccg);
+ void WriteCustomCommandLine(std::ostream& fout, std::string& fname,
+ cmCustomCommandGenerator const& ccg);
+ bool ComputeCustomCommandOrder(std::vector<cmSourceFile const*>& order);
+ bool VisitCustomCommand(std::set<cmSourceFile const*>& temp,
+ std::set<cmSourceFile const*>& perm,
+ std::vector<cmSourceFile const*>& order,
+ cmSourceFile const* sf);
void WriteSources(std::ostream& fout_proj);
void WriteSourceProperty(std::ostream& fout, const cmSourceFile* sf,
std::string const& propName,
std::string const& propFlag);
- void WriteReferences(std::ostream& fout);
static void WriteObjectLangOverride(std::ostream& fout,
const cmSourceFile* sourceFile);
@@ -71,7 +79,8 @@ private:
std::string TargetNameReal;
GhsMultiGpj::Types TagType;
std::string const Name;
- std::string ConfigName; /* CMAKE_BUILD_TYPE */
+ std::string ConfigName; /* CMAKE_BUILD_TYPE */
+ bool const CmdWindowsShell; /* custom commands run in cmd.exe or /bin/sh */
};
#endif // ! cmGhsMultiTargetGenerator_h
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index 9f361f6..b69dea0 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -265,14 +265,68 @@ void cmGlobalGhsMultiGenerator::WriteFileHeader(std::ostream& fout)
<< std::endl;
}
-void cmGlobalGhsMultiGenerator::WriteTopLevelProject(
- std::ostream& fout, cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators)
+void cmGlobalGhsMultiGenerator::WriteCustomRuleBOD(std::ostream& fout)
{
- WriteFileHeader(fout);
+ fout << "Commands {\n"
+ " Custom_Rule_Command {\n"
+ " name = \"Custom Rule Command\"\n"
+ " exec = \"";
+#ifdef _WIN32
+ fout << "cmd.exe";
+#else
+ fout << "/bin/sh";
+#endif
+ fout << "\"\n"
+ " options = {\"SpecialOptions\"}\n"
+ " }\n"
+ "}\n";
+
+ fout << "\n\n";
+ fout << "FileTypes {\n"
+ " CmakeRule {\n"
+ " name = \"Custom Rule\"\n"
+ " action = \"&Run\"\n"
+ " extensions = {\"";
+#ifdef _WIN32
+ fout << "bat";
+#else
+ fout << "sh";
+#endif
+ fout << "\"}\n"
+ " grepable = false\n"
+ " command = \"Custom Rule Command\"\n"
+ " commandLine = \"$COMMAND ";
+#ifdef _WIN32
+ fout << "/c";
+#endif
+ fout << " $INPUTFILE\"\n"
+ " progress = \"Processing Custom Rule\"\n"
+ " promoteToFirstPass = true\n"
+ " outputType = \"None\"\n"
+ " color = \"#800080\"\n"
+ " }\n"
+ "}\n";
+}
- this->WriteMacros(fout);
- this->WriteHighLevelDirectives(fout);
+void cmGlobalGhsMultiGenerator::WriteCustomTargetBOD(std::ostream& fout)
+{
+ fout << "FileTypes {\n"
+ " CmakeTarget {\n"
+ " name = \"Custom Target\"\n"
+ " action = \"&Execute\"\n"
+ " grepable = false\n"
+ " outputType = \"None\"\n"
+ " color = \"#800080\"\n"
+ " }\n"
+ "}\n";
+}
+
+void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout,
+ cmLocalGenerator* root)
+{
+ this->WriteFileHeader(fout);
+ this->WriteMacros(fout, root);
+ this->WriteHighLevelDirectives(root, fout);
GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fout);
fout << "# Top Level Project File" << std::endl;
@@ -298,71 +352,152 @@ void cmGlobalGhsMultiGenerator::WriteTopLevelProject(
}
fout << "\"" << this->OsDir << "\"" << std::endl;
}
-
- WriteSubProjects(fout, root, generators);
}
-void cmGlobalGhsMultiGenerator::WriteSubProjects(
- std::ostream& fout, cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators)
+void cmGlobalGhsMultiGenerator::WriteSubProjects(std::ostream& fout,
+ std::string& all_target)
{
- // Collect all targets under this root generator and the transitive
- // closure of their dependencies.
- TargetDependSet projectTargets;
- TargetDependSet originalTargets;
- this->GetTargetSets(projectTargets, originalTargets, root, generators);
- OrderedTargetDependSet orderedProjectTargets(projectTargets, "");
-
- // write out all the sub-projects
- std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
- for (cmGeneratorTarget const* target : orderedProjectTargets) {
- if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ fout << "CMakeFiles/" << all_target << " [Project]" << std::endl;
+ // All known targets
+ for (cmGeneratorTarget const* target : this->ProjectTargets) {
+ if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
+ target->GetName() != GetInstallTargetName())) {
continue;
}
+ fout << "CMakeFiles/" << target->GetName() + ".tgt" + FILE_EXTENSION
+ << " [Project]" << std::endl;
+ }
+}
- const char* projName = target->GetProperty("GENERATOR_FILE_NAME");
- const char* projType = target->GetProperty("GENERATOR_FILE_NAME_EXT");
- if (projName && projType) {
- cmLocalGenerator* lg = target->GetLocalGenerator();
- std::string dir = lg->GetCurrentBinaryDirectory();
- dir = root->MaybeConvertToRelativePath(rootBinaryDir, dir);
- if (dir == ".") {
- dir.clear();
- } else {
- if (dir.back() != '/') {
- dir += "/";
- }
+void cmGlobalGhsMultiGenerator::WriteProjectLine(
+ std::ostream& fout, cmGeneratorTarget const* target, cmLocalGenerator* root,
+ std::string& rootBinaryDir)
+{
+ const char* projName = target->GetProperty("GENERATOR_FILE_NAME");
+ const char* projType = target->GetProperty("GENERATOR_FILE_NAME_EXT");
+ if (projName && projType) {
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ std::string dir = lg->GetCurrentBinaryDirectory();
+ dir = root->MaybeConvertToRelativePath(rootBinaryDir, dir);
+ if (dir == ".") {
+ dir.clear();
+ } else {
+ if (dir.back() != '/') {
+ dir += "/";
}
+ }
- if (cmSystemTools::IsOn(target->GetProperty("EXCLUDE_FROM_ALL"))) {
- fout << "{comment} ";
- }
- std::string projFile = dir + projName + FILE_EXTENSION;
- fout << projFile;
- fout << " " << projType << std::endl;
+ std::string projFile = dir + projName + FILE_EXTENSION;
+ fout << projFile;
+ fout << " " << projType << std::endl;
+ } else {
+ /* Should never happen */
+ std::string message =
+ "The project file for target [" + target->GetName() + "] is missing.\n";
+ cmSystemTools::Error(message);
+ fout << "{comment} " << target->GetName() << " [missing project file]\n";
+ }
+}
- if (cmSystemTools::IsOn(target->GetProperty("GHS_REFERENCE_PROJECT"))) {
- // create reference project
- std::string fname = dir;
- fname += target->GetName();
- fname += "REF";
- fname += FILE_EXTENSION;
+void cmGlobalGhsMultiGenerator::WriteTargets(cmLocalGenerator* root)
+{
+ std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
+ rootBinaryDir += "/CMakeFiles";
+
+ // All known targets
+ for (cmGeneratorTarget const* target : this->ProjectTargets) {
+ if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
+ target->GetName() != GetInstallTargetName())) {
+ continue;
+ }
- cmGeneratedFileStream fref(fname);
- fref.SetCopyIfDifferent(true);
+ // create target build file
+ std::string name = target->GetName() + ".tgt" + FILE_EXTENSION;
+ std::string fname = rootBinaryDir + "/" + name;
+ cmGeneratedFileStream fbld(fname);
+ fbld.SetCopyIfDifferent(true);
+ this->WriteFileHeader(fbld);
+ GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld);
+ std::vector<cmGeneratorTarget const*> build;
+ if (ComputeTargetBuildOrder(target, build)) {
+ std::string message = "The inter-target dependency graph for target [" +
+ target->GetName() + "] had a cycle.\n";
+ cmSystemTools::Error(message);
+ } else {
+ for (auto& tgt : build) {
+ WriteProjectLine(fbld, tgt, root, rootBinaryDir);
+ }
+ }
+ fbld.Close();
+ }
+}
- this->WriteFileHeader(fref);
- GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fref);
- fref << " :reference=" << projFile << std::endl;
+void cmGlobalGhsMultiGenerator::WriteAllTarget(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators,
+ std::string& all_target)
+{
+ this->ProjectTargets.clear();
+
+ // create target build file
+ all_target = root->GetProjectName() + "." + this->GetAllTargetName() +
+ ".tgt" + FILE_EXTENSION;
+ std::string fname =
+ root->GetCurrentBinaryDirectory() + "/CMakeFiles/" + all_target;
+ cmGeneratedFileStream fbld(fname);
+ fbld.SetCopyIfDifferent(true);
+ this->WriteFileHeader(fbld);
+ GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld);
- fref.Close();
+ // Collect all targets under this root generator and the transitive
+ // closure of their dependencies.
+ TargetDependSet projectTargets;
+ TargetDependSet originalTargets;
+ this->GetTargetSets(projectTargets, originalTargets, root, generators);
+ OrderedTargetDependSet sortedProjectTargets(projectTargets, "");
+ std::vector<cmGeneratorTarget const*> defaultTargets;
+ for (cmGeneratorTarget const* t : sortedProjectTargets) {
+ /* save list of all targets in sorted order */
+ this->ProjectTargets.push_back(t);
+ }
+ for (cmGeneratorTarget const* t : sortedProjectTargets) {
+ if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ continue;
+ }
+ if (!cmSystemTools::IsOn(t->GetProperty("EXCLUDE_FROM_ALL"))) {
+ defaultTargets.push_back(t);
+ }
+ }
+ std::vector<cmGeneratorTarget const*> build;
+ if (ComputeTargetBuildOrder(defaultTargets, build)) {
+ std::string message = "The inter-target dependency graph for project [" +
+ root->GetProjectName() + "] had a cycle.\n";
+ cmSystemTools::Error(message);
+ } else {
+ // determine the targets for ALL target
+ std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
+ rootBinaryDir += "/CMakeFiles";
+ for (cmGeneratorTarget const* target : build) {
+ if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ target->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ continue;
}
+ this->WriteProjectLine(fbld, target, root, rootBinaryDir);
}
}
+ fbld.Close();
}
void cmGlobalGhsMultiGenerator::Generate()
{
+ std::string fname;
+
// first do the superclass method
this->cmGlobalGenerator::Generate();
@@ -370,11 +505,32 @@ void cmGlobalGhsMultiGenerator::Generate()
for (auto& it : this->ProjectMap) {
this->OutputTopLevelProject(it.second[0], it.second);
}
+
+ // create custom rule BOD file
+ fname = this->GetCMakeInstance()->GetHomeOutputDirectory() +
+ "/CMakeFiles/custom_rule.bod";
+ cmGeneratedFileStream frule(fname);
+ frule.SetCopyIfDifferent(true);
+ this->WriteFileHeader(frule);
+ this->WriteCustomRuleBOD(frule);
+ frule.Close();
+
+ // create custom target BOD file
+ fname = this->GetCMakeInstance()->GetHomeOutputDirectory() +
+ "/CMakeFiles/custom_target.bod";
+ cmGeneratedFileStream ftarget(fname);
+ ftarget.SetCopyIfDifferent(true);
+ this->WriteFileHeader(ftarget);
+ this->WriteCustomTargetBOD(ftarget);
+ ftarget.Close();
}
void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
{
+ std::string fname;
+ std::string all_target;
+
if (generators.empty()) {
return;
}
@@ -383,18 +539,21 @@ void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
* with target projects. This avoid the issue where the project has
* the same name as the executable target.
*/
- std::string fname = root->GetCurrentBinaryDirectory();
+ fname = root->GetCurrentBinaryDirectory();
fname += "/";
fname += root->GetProjectName();
fname += ".top";
fname += FILE_EXTENSION;
- cmGeneratedFileStream fout(fname);
- fout.SetCopyIfDifferent(true);
+ cmGeneratedFileStream top(fname);
+ top.SetCopyIfDifferent(true);
+ this->WriteTopLevelProject(top, root);
- this->WriteTopLevelProject(fout, root, generators);
+ this->WriteAllTarget(root, generators, all_target);
+ this->WriteTargets(root);
- fout.Close();
+ this->WriteSubProjects(top, all_target);
+ top.Close();
}
std::vector<cmGlobalGenerator::GeneratedMakeCommand>
@@ -426,6 +585,9 @@ cmGlobalGhsMultiGenerator::GenerateBuildCommand(
std::vector<std::string> files;
cmSystemTools::Glob(projectDir, ".*\\.top\\.gpj", files);
if (!files.empty()) {
+ /* if multiple top-projects are found in build directory
+ * then prefer projectName top-project.
+ */
auto p = std::find(files.begin(), files.end(), proj);
if (p == files.end()) {
proj = files.at(0);
@@ -440,20 +602,24 @@ cmGlobalGhsMultiGenerator::GenerateBuildCommand(
} else {
for (const auto& tname : targetNames) {
if (!tname.empty()) {
- if (tname.compare(tname.size() - 4, 4, ".gpj") == 0) {
- makeCommand.Add(tname);
- } else {
- makeCommand.Add(tname + ".gpj");
- }
+ makeCommand.Add(tname + ".tgt.gpj");
}
}
}
+ } else {
+ /* transform name to default build */;
+ std::string all = proj;
+ all.replace(all.end() - 7, all.end(),
+ std::string(this->GetAllTargetName()) + ".tgt.gpj");
+ makeCommand.Add(all);
}
return { makeCommand };
}
-void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout)
+void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout,
+ cmLocalGenerator* root)
{
+ fout << "macro PROJ_NAME=" << root->GetProjectName() << std::endl;
char const* ghsGpjMacros =
this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS");
if (nullptr != ghsGpjMacros) {
@@ -465,13 +631,14 @@ void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout)
}
}
-void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(std::ostream& fout)
+void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(
+ cmLocalGenerator* root, std::ostream& fout)
{
/* set primary target */
std::string tgt;
const char* t =
this->GetCMakeInstance()->GetCacheDefinition("GHS_PRIMARY_TARGET");
- if (t) {
+ if (t && *t != '\0') {
tgt = t;
this->GetCMakeInstance()->MarkCliAsUsed("GHS_PRIMARY_TARGET");
} else {
@@ -486,16 +653,20 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(std::ostream& fout)
}
fout << "primaryTarget=" << tgt << std::endl;
+ fout << "customization=" << root->GetBinaryDirectory()
+ << "/CMakeFiles/custom_rule.bod" << std::endl;
+ fout << "customization=" << root->GetBinaryDirectory()
+ << "/CMakeFiles/custom_target.bod" << std::endl;
char const* const customization =
this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION");
if (nullptr != customization && strlen(customization) > 0) {
- fout << "customization=" << trimQuotes(customization) << std::endl;
+ fout << "customization=" << this->TrimQuotes(customization) << std::endl;
this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
}
}
-std::string cmGlobalGhsMultiGenerator::trimQuotes(std::string const& str)
+std::string cmGlobalGhsMultiGenerator::TrimQuotes(std::string const& str)
{
std::string result;
result.reserve(str.size());
@@ -528,3 +699,56 @@ cmGlobalGhsMultiGenerator::OrderedTargetDependSet::OrderedTargetDependSet(
{
this->insert(targets.begin(), targets.end());
}
+
+bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
+ cmGeneratorTarget const* tgt, std::vector<cmGeneratorTarget const*>& build)
+{
+ std::vector<cmGeneratorTarget const*> t{ tgt };
+ return ComputeTargetBuildOrder(t, build);
+}
+
+bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
+ std::vector<cmGeneratorTarget const*>& tgt,
+ std::vector<cmGeneratorTarget const*>& build)
+{
+ std::set<cmGeneratorTarget const*> temp;
+ std::set<cmGeneratorTarget const*> perm;
+
+ for (auto ti : tgt) {
+ bool r = VisitTarget(temp, perm, build, ti);
+ if (r) {
+ return r;
+ }
+ }
+ return false;
+}
+
+bool cmGlobalGhsMultiGenerator::VisitTarget(
+ std::set<cmGeneratorTarget const*>& temp,
+ std::set<cmGeneratorTarget const*>& perm,
+ std::vector<cmGeneratorTarget const*>& order, cmGeneratorTarget const* ti)
+{
+ /* check if permanent mark is set*/
+ if (perm.find(ti) == perm.end()) {
+ /* set temporary mark; check if revisit*/
+ if (temp.insert(ti).second) {
+ /* sort targets lexicographically to ensure that nodes are always visited
+ * in the same order */
+ OrderedTargetDependSet sortedTargets(this->GetTargetDirectDepends(ti),
+ "");
+ for (auto& di : sortedTargets) {
+ if (this->VisitTarget(temp, perm, order, di)) {
+ return true;
+ }
+ }
+ /* mark as complete; insert into beginning of list*/
+ perm.insert(ti);
+ order.push_back(ti);
+ return false;
+ }
+ /* revisiting item - not a DAG */
+ return true;
+ }
+ /* already complete */
+ return false;
+}
diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h
index 1aeb1dc..98358c7 100644
--- a/Source/cmGlobalGhsMultiGenerator.h
+++ b/Source/cmGlobalGhsMultiGenerator.h
@@ -78,23 +78,7 @@ public:
// Write the common disclaimer text at the top of each build file.
void WriteFileHeader(std::ostream& fout);
- // Target dependency sorting
- class TargetSet : public std::set<cmGeneratorTarget const*>
- {
- };
- class TargetCompare
- {
- std::string First;
-
- public:
- TargetCompare(std::string first)
- : First(std::move(first))
- {
- }
- bool operator()(cmGeneratorTarget const* l,
- cmGeneratorTarget const* r) const;
- };
- class OrderedTargetDependSet;
+ const char* GetInstallTargetName() const override { return "install"; }
protected:
void Generate() override;
@@ -111,18 +95,53 @@ private:
/* top-level project */
void OutputTopLevelProject(cmLocalGenerator* root,
std::vector<cmLocalGenerator*>& generators);
- void WriteTopLevelProject(std::ostream& fout, cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators);
- void WriteMacros(std::ostream& fout);
- void WriteHighLevelDirectives(std::ostream& fout);
- void WriteSubProjects(std::ostream& fout, cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators);
-
- std::string trimQuotes(std::string const& str);
+ void WriteTopLevelProject(std::ostream& fout, cmLocalGenerator* root);
+ void WriteMacros(std::ostream& fout, cmLocalGenerator* root);
+ void WriteHighLevelDirectives(cmLocalGenerator* root, std::ostream& fout);
+ void WriteSubProjects(std::ostream& fout, std::string& all_target);
+ void WriteTargets(cmLocalGenerator* root);
+ void WriteProjectLine(std::ostream& fout, cmGeneratorTarget const* target,
+ cmLocalGenerator* root, std::string& rootBinaryDir);
+ void WriteCustomRuleBOD(std::ostream& fout);
+ void WriteCustomTargetBOD(std::ostream& fout);
+ void WriteAllTarget(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators,
+ std::string& all_target);
+
+ std::string TrimQuotes(std::string const& str);
std::string OsDir;
static const char* DEFAULT_BUILD_PROGRAM;
static const char* DEFAULT_TOOLSET_ROOT;
+
+ bool ComputeTargetBuildOrder(cmGeneratorTarget const* tgt,
+ std::vector<cmGeneratorTarget const*>& build);
+ bool ComputeTargetBuildOrder(std::vector<cmGeneratorTarget const*>& tgt,
+ std::vector<cmGeneratorTarget const*>& build);
+ bool VisitTarget(std::set<cmGeneratorTarget const*>& temp,
+ std::set<cmGeneratorTarget const*>& perm,
+ std::vector<cmGeneratorTarget const*>& order,
+ cmGeneratorTarget const* ti);
+
+ std::vector<cmGeneratorTarget const*> ProjectTargets;
+
+ // Target sorting
+ class TargetSet : public std::set<cmGeneratorTarget const*>
+ {
+ };
+ class TargetCompare
+ {
+ std::string First;
+
+ public:
+ TargetCompare(std::string first)
+ : First(std::move(first))
+ {
+ }
+ bool operator()(cmGeneratorTarget const* l,
+ cmGeneratorTarget const* r) const;
+ };
+ class OrderedTargetDependSet;
};
class cmGlobalGhsMultiGenerator::OrderedTargetDependSet
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 3746965..2e0902c 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -2336,7 +2336,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
endmacro()
macro(add_test_GhsMulti_rename_install test_name)
add_test_GhsMulti( ${test_name} GhsMultiRenameInstall ${test_name}
- "-DCMAKE_INSTALL_PREFIX=. -DRUN_TEST=${test_name}" ${CMAKE_CMAKE_COMMAND} -P ./cmake_install.cmake)
+ "-DCMAKE_INSTALL_PREFIX=. -DRUN_TEST=${test_name}" ${CMAKE_CMAKE_COMMAND} --build . --target install)
endmacro()
#unset ghs config variables
unset(ghs_config_name)
@@ -2391,6 +2391,9 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
add_test_GhsMulti(compiler_options_kernel GhsMultiCompilerOptions Kernel "-DRUN_TEST=KERNEL_FLAGS -DRUN_TEST_BUILD_TYPE=DEBUG")
add_test_GhsMulti(try_compile_copy GhsMultiCopyFile "" "")
add_test_GhsMulti(ghs_platform GhsMultiPlatform "" "")
+ add_test_GhsMulti(custom_target GhsMultiCustomTarget "" "")
+ add_test_GhsMulti(dep_order GhsMultiDepOrder "" "")
+ add_test_GhsMulti(external_project GhsMultiExternalProject "" "")
list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/GhsMulti/${ghs_config_name}")
#unset ghs config variables
unset(ghs_config_name)
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt
new file mode 100644
index 0000000..93d668b
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt
@@ -0,0 +1,110 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+# Tests assume no previous builds in the build directory
+file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/build)
+
+macro (test_output)
+ if (BUILD_OUTPUT STREQUAL EXPECTED_LINES )
+ message("Build OK")
+ else()
+ message("BUILD_OUTPUT")
+ foreach(Line IN LISTS BUILD_OUTPUT)
+ message("${Line}")
+ endforeach()
+ message("EXPECTED_LINES")
+ foreach(Line IN LISTS EXPECTED_LINES)
+ message("${Line}")
+ endforeach()
+ message(SEND_ERROR "Build KO")
+ endif()
+endmacro()
+
+message("Copy project")
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt.in
+ ${CMAKE_CURRENT_BINARY_DIR}/src/CMakeLists.txt COPYONLY)
+
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/exe1.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/lib1.c
+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/src
+)
+
+message("Building ALL target")
+try_compile(RESULT
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_BINARY_DIR}/src
+ test
+ CMAKE_FLAGS
+ -DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}
+ OUTPUT_VARIABLE BUILD_OUTPUT)
+
+message("Output from build:\n${BUILD_OUTPUT}")
+
+#filter outputs
+string(REPLACE "\r" "" BUILD_OUTPUT "${BUILD_OUTPUT}")
+string(REPLACE "\n" ";" BUILD_OUTPUT "${BUILD_OUTPUT}")
+list(FILTER BUILD_OUTPUT INCLUDE REGEX "^.*CT:")
+
+unset(EXPECTED_LINES)
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_postbuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_cmd")
+list(APPEND EXPECTED_LINES "CT: Processing target_cmd_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_cmd_postbuild")
+
+test_output()
+
+message("Building target_update_files target")
+try_compile(RESULT
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_BINARY_DIR}/src
+ test target_update_files
+ CMAKE_FLAGS
+ -DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}
+ OUTPUT_VARIABLE BUILD_OUTPUT)
+
+message("Output from build:\n${BUILD_OUTPUT}")
+
+#filter outputs
+string(REPLACE "\r" "" BUILD_OUTPUT "${BUILD_OUTPUT}")
+string(REPLACE "\n" ";" BUILD_OUTPUT "${BUILD_OUTPUT}")
+list(FILTER BUILD_OUTPUT INCLUDE REGEX "^.*CT:")
+
+unset(EXPECTED_LINES)
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_postbuild")
+list(APPEND EXPECTED_LINES "CT: generate C file another_file")
+list(APPEND EXPECTED_LINES "CT: generate text file dependsA")
+list(APPEND EXPECTED_LINES "CT: generate text file out_of_order_dep")
+list(APPEND EXPECTED_LINES "CT: generate text files A, B, and C")
+list(APPEND EXPECTED_LINES "CT: Processing target_update_files")
+
+test_output()
+
+message("Rerun target_update_files target")
+try_compile(RESULT
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_BINARY_DIR}/src
+ test target_update_files
+ CMAKE_FLAGS
+ -DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}
+ OUTPUT_VARIABLE BUILD_OUTPUT)
+
+message("Output from build:\n${BUILD_OUTPUT}")
+
+#filter outputs
+string(REPLACE "\r" "" BUILD_OUTPUT "${BUILD_OUTPUT}")
+string(REPLACE "\n" ";" BUILD_OUTPUT "${BUILD_OUTPUT}")
+list(FILTER BUILD_OUTPUT INCLUDE REGEX "^.*CT:")
+
+unset(EXPECTED_LINES)
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_postbuild")
+list(APPEND EXPECTED_LINES "CT: generate text files A, B, and C")
+list(APPEND EXPECTED_LINES "CT: Processing target_update_files")
+
+test_output()
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt.in b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt.in
new file mode 100644
index 0000000..fed946c
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt.in
@@ -0,0 +1,108 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+ add_link_options("-non_shared")
+endif()
+
+add_library(lib1 lib1.c)
+
+set(TEST_MISSING_TARGET_SRC 0)
+set(TEST_MISSING_TARGET_DEP 0)
+set(TEST_MISSING_DEP 0)
+set(TEST_DEP_CYCLE 0)
+
+add_executable(exe1 exe1.c)
+target_link_libraries(exe1 lib1)
+
+add_custom_target(target_cmd ALL
+ COMMAND ${CMAKE_COMMAND} -E echo "target_cmd" > target_cmd
+ COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_extra" > target_cmd_extra.txt
+ BYPRODUCTS target_cmd target_cmd_extra.txt
+ COMMENT "CT: Processing target_cmd")
+
+add_custom_command(TARGET target_cmd PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_prebuild" > target_cmd_prebuild.txt
+ BYPRODUCTS target_cmd_prebuild.txt
+ COMMENT "CT: Processing target_cmd_prebuild")
+#event does not run for custom targets
+add_custom_command(TARGET target_cmd PRE_LINK
+ COMMAND ${CMAKE_COMMAND} -E echo "executing target_cmd_prelink commands"
+ COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_prelink" > target_cmd_prelink.txt
+ BYPRODUCTS target_cmd_prelink.txt
+ COMMENT "CT: Processing target_cmd_prelink")
+add_custom_command(TARGET target_cmd POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "executing target_cmd_postbuild commands"
+ COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_postbuild" > target_cmd_postbuild.txt
+ BYPRODUCTS target_cmd_postbuild.txt
+ COMMENT "CT: Processing target_cmd_postbuild")
+
+add_custom_target(target_empty ALL
+ COMMENT "CT: Processing target_empty")
+
+add_custom_command(TARGET target_empty PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "target_empty_prebuild" > target_empty_prebuild.txt
+ BYPRODUCTS target_empty_prebuild.txt
+ COMMENT "CT: Processing target_empty_prebuild")
+add_custom_command(TARGET target_empty POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "target_empty_postbuild" > target_empty_postbuild.txt
+ BYPRODUCTS target_empty_postbuild.txt
+ COMMENT "CT: Processing target_empty_postbuild")
+
+add_dependencies(target_cmd target_empty)
+
+add_custom_command(
+ OUTPUT out_of_order_dep.txt
+ COMMAND ${CMAKE_COMMAND} -E echo "out_of_order_dep" > out_of_order_dep.txt
+ COMMENT "CT: generate text file out_of_order_dep"
+ DEPENDS dependsA.txt
+)
+
+if(TEST_MISSING_TARGET_SRC)
+ set(SRC_FILE does_not_exist)
+endif()
+if(TEST_MISSING_TARGET_DEP)
+ set(DEP_FILE does_not_exist)
+endif()
+
+add_custom_target(target_update_files
+ DEPENDS genc_do_not_list.txt ${DEP_FILE}
+ SOURCES gena.txt genb.txt another_file.c ${SRC_FILE}
+ BYPRODUCTS junkit.txt
+ COMMAND ${CMAKE_COMMAND} -E copy another_file.c junkit.txt
+ COMMENT "CT: Processing target_update_files")
+
+add_custom_command(
+ OUTPUT force_rebuild gena.txt genb.txt genc_do_not_list.txt
+ COMMAND ${CMAKE_COMMAND} -E copy dependsA.txt gena.txt
+ COMMAND ${CMAKE_COMMAND} -E echo "genb" > genb.txt
+ COMMAND ${CMAKE_COMMAND} -E echo "genc" > genc_do_not_list.txt
+ DEPENDS out_of_order_dep.txt dependsA.txt
+ COMMENT "CT: generate text files A, B, and C"
+)
+
+if(TEST_MISSING_DEP)
+ set(MISSING_DEP MISSING_DEP)
+endif()
+if(TEST_DEP_CYCLE)
+ set(DEP_CYCLE out_of_order_dep.txt)
+endif()
+
+add_custom_command(
+ OUTPUT dependsA.txt
+ COMMAND ${CMAKE_COMMAND} -E echo "dependsA" > dependsA.txt
+ DEPENDS ${MISSING_DEP} ${DEP_CYCLE} another_file.c
+ COMMENT "CT: generate text file dependsA"
+)
+
+add_custom_command(
+ OUTPUT another_file.c
+ COMMAND ${CMAKE_COMMAND} -E echo "//auto-gen file" > another_file.c
+ COMMENT "CT: generate C file another_file"
+)
+
+add_dependencies(target_update_files target_empty)
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/exe1.c b/Tests/GhsMulti/GhsMultiCustomTarget/exe1.c
new file mode 100644
index 0000000..29ad70a
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/exe1.c
@@ -0,0 +1,5 @@
+extern int func(void);
+int main(void)
+{
+ return func();
+}
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/lib1.c b/Tests/GhsMulti/GhsMultiCustomTarget/lib1.c
new file mode 100644
index 0000000..b35e9cc
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/lib1.c
@@ -0,0 +1,4 @@
+int func(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/CMakeLists.txt
new file mode 100644
index 0000000..2e2871b
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/CMakeLists.txt
@@ -0,0 +1,12 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+#set_property( GLOBAL PROPERTY GLOBAL_DEPENDS_DEBUG_MODE 1)
+add_subdirectory(exec)
+add_subdirectory(lib)
+add_subdirectory(protolib)
+add_dependencies(lib1 proto)
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/exec/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/exec/CMakeLists.txt
new file mode 100644
index 0000000..85ee805
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/exec/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+add_executable(exe1 exe1.c)
+target_link_libraries(exe1 lib1)
+target_include_directories(exe1 PRIVATE "${test_BINARY_DIR}")
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+ target_link_options(exe1 PRIVATE "-non_shared")
+endif()
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/exec/exe1.c b/Tests/GhsMulti/GhsMultiDepOrder/exec/exe1.c
new file mode 100644
index 0000000..fbf4ed4
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/exec/exe1.c
@@ -0,0 +1,8 @@
+#include "lib1.h"
+#include "p.h"
+
+int main(void)
+{
+ return func1() + func2() + func3() + func1p() + func2p() + func3p() +
+ PROTO1 + PROTO2 + PROTO3;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/lib/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/lib/CMakeLists.txt
new file mode 100644
index 0000000..ae30fa2
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/lib/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+add_library(lib1 STATIC
+ func1.c lib1.h
+ "${test_BINARY_DIR}/protolib/proto1.c"
+ "${test_BINARY_DIR}/protolib/proto1.h")
+set_source_files_properties(
+ "${test_BINARY_DIR}/protolib/proto1.c"
+ "${test_BINARY_DIR}/protolib/proto1.h"
+ PROPERTIES GENERATED 1)
+target_include_directories(lib1 PRIVATE "${test_BINARY_DIR}/protolib"
+ PUBLIC .)
+add_custom_command( TARGET lib1 POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${test_BINARY_DIR}/protolib/proto1.h" "${test_BINARY_DIR}/p.h"
+ COMMENT "Copy ${test_BINARY_DIR}/protolib/proto1.h ${test_BINARY_DIR}/p.h"
+ BYPRODUCTS "${test_BINARY_DIR}/p.h")
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/lib/func1.c b/Tests/GhsMulti/GhsMultiDepOrder/lib/func1.c
new file mode 100644
index 0000000..53334fe
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/lib/func1.c
@@ -0,0 +1,17 @@
+#include "lib1.h"
+#include "proto1.h"
+
+int func1(void)
+{
+ return 1 + PROTO1;
+}
+
+int func2(void)
+{
+ return 2 + PROTO2;
+}
+
+int func3(void)
+{
+ return 3 + PROTO3;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/lib/lib1.h b/Tests/GhsMulti/GhsMultiDepOrder/lib/lib1.h
new file mode 100644
index 0000000..5e99f02
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/lib/lib1.h
@@ -0,0 +1,3 @@
+extern int func1(void);
+extern int func2(void);
+extern int func3(void);
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/protolib/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/protolib/CMakeLists.txt
new file mode 100644
index 0000000..8cb6869
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/protolib/CMakeLists.txt
@@ -0,0 +1,28 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+add_custom_target(proto ALL
+ DEPENDS proto1.c
+ proto1.h
+ SOURCES
+ ${test_SOURCE_DIR}/protolib/proto1.c.in
+ ${test_SOURCE_DIR}/protolib/proto1.h.in
+ COMMENT "Creating proto files")
+
+add_custom_command(
+ OUTPUT proto1.c
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${test_SOURCE_DIR}/protolib/proto1.c.in proto1.c
+ DEPENDS ${test_SOURCE_DIR}/protolib/proto1.c.in
+ COMMENT "generate proto C files"
+)
+
+add_custom_command(
+ OUTPUT proto1.h
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${test_SOURCE_DIR}/protolib/proto1.h.in proto1.h
+ DEPENDS ${test_SOURCE_DIR}/protolib/proto1.h.in
+ COMMENT "generate proto H files"
+)
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.c.in b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.c.in
new file mode 100644
index 0000000..0efb1bd
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.c.in
@@ -0,0 +1,16 @@
+#include "proto1.h"
+
+int func1p(void)
+{
+ return 1;
+}
+
+int func2p(void)
+{
+ return 2;
+}
+
+int func3p(void)
+{
+ return 3;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.h.in b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.h.in
new file mode 100644
index 0000000..f2f93af
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.h.in
@@ -0,0 +1,7 @@
+extern int func1p(void);
+extern int func2p(void);
+extern int func3p(void);
+
+#define PROTO1 0x1
+#define PROTO2 0x2
+#define PROTO3 0x3
diff --git a/Tests/GhsMulti/GhsMultiExternalProject/CMakeLists.txt b/Tests/GhsMulti/GhsMultiExternalProject/CMakeLists.txt
new file mode 100644
index 0000000..24126c8
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiExternalProject/CMakeLists.txt
@@ -0,0 +1,14 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+include(ExternalProject)
+
+ExternalProject_Add(another_project
+ SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/empty
+ BINARY_DIR empty_build
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ )
diff --git a/Tests/GhsMulti/GhsMultiExternalProject/empty/CMakeLists.txt b/Tests/GhsMulti/GhsMultiExternalProject/empty/CMakeLists.txt
new file mode 100644
index 0000000..6846a98
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiExternalProject/empty/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(empty NONE)
+
+message("EMPTY PROJECT")
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt
index e431217..3837b5a 100644
--- a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt
@@ -1,4 +1,3 @@
add_executable(App Main.c)
-target_include_directories(App PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../Lib)
target_link_libraries(App Lib)
target_compile_options(App PUBLIC "-non_shared")
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt
index 00e0f59..bb9849a 100644
--- a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt
@@ -1 +1,2 @@
add_library(Lib HelperFun.c HelperFun.h)
+target_include_directories(Lib PUBLIC .)
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt
index c5db155..3f2f0eb 100644
--- a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt
@@ -18,3 +18,4 @@ target_link_options(kernel PRIVATE -kernel)
# create monolith INTEGRITY application
add_executable(monolith test.int)
+add_dependencies(monolith vas)
diff --git a/Tests/GhsMulti/GhsMultiPlatform/file1.c b/Tests/GhsMulti/GhsMultiPlatform/file1.c
deleted file mode 100644
index 4132aa4..0000000
--- a/Tests/GhsMulti/GhsMultiPlatform/file1.c
+++ /dev/null
@@ -1,4 +0,0 @@
-int main(void)
-{
- return -42;
-}
diff --git a/Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt b/Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt
index f5792b4..b2540d9 100644
--- a/Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt
@@ -13,7 +13,7 @@ endif()
if(RUN_TEST STREQUAL "SINGLE_EXEC")
add_executable(exe1 exe.c)
- set(targets_to_install ${targets_to_install} exe1)
+ set(targets_to_install exe1)
endif()
if(RUN_TEST STREQUAL "SINGLE_EXEC_RENAMED")
@@ -22,7 +22,7 @@ if(RUN_TEST STREQUAL "SINGLE_EXEC_RENAMED")
set_property(TARGET exe1 PROPERTY RUNTIME_OUTPUT_DIRECTORY ${name}_bin_$<CONFIG>)
set_property(TARGET exe1 PROPERTY OUTPUT_NAME ${name}_$<CONFIG>)
set_property(TARGET exe1 PROPERTY SUFFIX .bin)
- set(targets_to_install ${targets_to_install} exe1)
+ set(targets_to_install exe1)
endif()
if(RUN_TEST STREQUAL "EXEC_AND_LIB")
@@ -33,7 +33,7 @@ if(RUN_TEST STREQUAL "EXEC_AND_LIB")
add_executable(exe1 exe1.c)
target_link_libraries(exe1 lib1)
- set(targets_to_install ${targets_to_install} exe1 lib1)
+ set(targets_to_install exe1 lib1)
endif()
install(TARGETS ${targets_to_install}
diff --git a/Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt b/Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt
index ed3094b..f5f3c55 100644
--- a/Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt
@@ -5,8 +5,6 @@ cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(test C)
-add_custom_target(testTarget ALL echo this is a test)
-
add_library(sharedLib SHARED file.c)
add_library(moduleLib MODULE file.c)