1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3 #include "cmGhsMultiTargetGenerator.h"
13 #include <cm/optional>
15 #include "cmCustomCommand.h"
16 #include "cmCustomCommandGenerator.h"
17 #include "cmGeneratedFileStream.h"
18 #include "cmGeneratorTarget.h"
19 #include "cmGlobalGhsMultiGenerator.h"
20 #include "cmLinkLineComputer.h" // IWYU pragma: keep
22 #include "cmLocalGenerator.h"
23 #include "cmLocalGhsMultiGenerator.h"
24 #include "cmMakefile.h"
25 #include "cmOutputConverter.h"
26 #include "cmSourceFile.h"
27 #include "cmSourceFileLocation.h"
28 #include "cmSourceGroup.h"
29 #include "cmStateDirectory.h"
30 #include "cmStateSnapshot.h"
31 #include "cmStateTypes.h"
32 #include "cmStringAlgorithms.h"
33 #include "cmSystemTools.h"
37 cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget
* target
)
38 : GeneratorTarget(target
)
40 static_cast<cmLocalGhsMultiGenerator
*>(target
->GetLocalGenerator()))
41 , Makefile(target
->Target
->GetMakefile())
42 , Name(target
->GetName())
44 // Store the configuration name that is being used
45 if (cmValue config
= this->Makefile
->GetDefinition("CMAKE_BUILD_TYPE")) {
46 // Use the build type given by the user.
47 this->ConfigName
= *config
;
49 // No configuration type given.
50 this->ConfigName
.clear();
54 cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator() = default;
56 void cmGhsMultiTargetGenerator::Generate()
58 // Determine type of target for this project
59 switch (this->GeneratorTarget
->GetType()) {
60 case cmStateEnums::EXECUTABLE
: {
61 // Get the name of the executable to generate.
62 this->TargetNameReal
=
63 this->GeneratorTarget
->GetExecutableNames(this->ConfigName
).Real
;
64 if (this->cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()) {
65 this->TagType
= GhsMultiGpj::INTERGRITY_APPLICATION
;
67 this->TagType
= GhsMultiGpj::PROGRAM
;
71 case cmStateEnums::STATIC_LIBRARY
: {
72 this->TargetNameReal
=
73 this->GeneratorTarget
->GetLibraryNames(this->ConfigName
).Real
;
74 this->TagType
= GhsMultiGpj::LIBRARY
;
77 case cmStateEnums::SHARED_LIBRARY
: {
79 cmStrCat("add_library(<name> SHARED ...) not supported: ", this->Name
);
80 cmSystemTools::Message(msg
);
83 case cmStateEnums::OBJECT_LIBRARY
: {
84 this->TargetNameReal
=
85 this->GeneratorTarget
->GetLibraryNames(this->ConfigName
).Real
;
86 this->TagType
= GhsMultiGpj::SUBPROJECT
;
89 case cmStateEnums::MODULE_LIBRARY
: {
91 cmStrCat("add_library(<name> MODULE ...) not supported: ", this->Name
);
92 cmSystemTools::Message(msg
);
95 case cmStateEnums::UTILITY
: {
96 this->TargetNameReal
= this->GeneratorTarget
->GetName();
97 this->TagType
= GhsMultiGpj::CUSTOM_TARGET
;
100 case cmStateEnums::GLOBAL_TARGET
: {
101 this->TargetNameReal
= this->GeneratorTarget
->GetName();
102 if (this->TargetNameReal
==
103 this->GetGlobalGenerator()->GetInstallTargetName()) {
104 this->TagType
= GhsMultiGpj::CUSTOM_TARGET
;
114 this->GenerateTarget();
117 void cmGhsMultiTargetGenerator::GenerateTarget()
119 if (this->GeneratorTarget
->GetType() == cmStateEnums::EXECUTABLE
&&
120 !this->GeneratorTarget
121 ->GetLinkerTypeProperty(
122 this->GeneratorTarget
->GetLinkerLanguage(this->ConfigName
),
125 // Green Hill MULTI does not support this feature.
126 cmSystemTools::Message(
127 cmStrCat("'LINKER_TYPE' property, specified on target '",
128 this->GeneratorTarget
->GetName(),
129 "', is not supported by this generator."));
132 // Open the target file in copy-if-different mode.
134 cmStrCat(this->LocalGenerator
->GetCurrentBinaryDirectory(), '/',
135 this->LocalGenerator
->GetTargetDirectory(this->GeneratorTarget
),
136 '/', this->Name
, cmGlobalGhsMultiGenerator::FILE_EXTENSION
);
138 // Tell the global generator the name of the project file
139 this->GeneratorTarget
->Target
->SetProperty("GENERATOR_FILE_NAME", fproj
);
140 this->GeneratorTarget
->Target
->SetProperty(
141 "GENERATOR_FILE_NAME_EXT", GhsMultiGpj::GetGpjTag(this->TagType
));
143 cmGeneratedFileStream
fout(fproj
);
144 fout
.SetCopyIfDifferent(true);
146 this->GetGlobalGenerator()->WriteFileHeader(fout
);
147 GhsMultiGpj::WriteGpjTag(this->TagType
, fout
);
149 if (this->TagType
!= GhsMultiGpj::CUSTOM_TARGET
) {
150 const std::string
language(
151 this->GeneratorTarget
->GetLinkerLanguage(this->ConfigName
));
152 this->WriteTargetSpecifics(fout
, this->ConfigName
);
153 this->SetCompilerFlags(this->ConfigName
, language
);
154 this->WriteCompilerFlags(fout
, this->ConfigName
, language
);
155 this->WriteCompilerDefinitions(fout
, this->ConfigName
, language
);
156 this->WriteIncludes(fout
, this->ConfigName
, language
);
157 this->WriteTargetLinkLine(fout
, this->ConfigName
);
158 this->WriteBuildEvents(fout
);
160 this->WriteSources(fout
);
164 cmGlobalGhsMultiGenerator
* cmGhsMultiTargetGenerator::GetGlobalGenerator()
167 return static_cast<cmGlobalGhsMultiGenerator
*>(
168 this->LocalGenerator
->GetGlobalGenerator());
171 void cmGhsMultiTargetGenerator::WriteTargetSpecifics(std::ostream
& fout
,
172 const std::string
& config
)
176 /* Determine paths from the target project file to where the output artifacts
177 * need to be located.
179 if (this->TagType
!= GhsMultiGpj::SUBPROJECT
) {
180 // set target binary file destination
181 std::string binpath
= cmStrCat(
182 this->LocalGenerator
->GetCurrentBinaryDirectory(), '/',
183 this->LocalGenerator
->GetTargetDirectory(this->GeneratorTarget
));
184 outpath
= cmSystemTools::RelativePath(
185 binpath
, this->GeneratorTarget
->GetDirectory(config
));
186 /* clang-format off */
187 fout
<< " :binDirRelative=\"" << outpath
<< "\"\n"
188 " -o \"" << this->TargetNameReal
<< "\"\n";
189 /* clang-format on */
192 // set target object file destination
194 fout
<< " :outputDirRelative=\"" << outpath
<< "\"\n";
197 void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string
const& config
,
198 const std::string
& language
)
200 auto i
= this->FlagsByLanguage
.find(language
);
201 if (i
== this->FlagsByLanguage
.end()) {
203 this->LocalGenerator
->AddLanguageFlags(
204 flags
, this->GeneratorTarget
, cmBuildStep::Compile
, language
, config
);
205 this->LocalGenerator
->AddCMP0018Flags(flags
, this->GeneratorTarget
,
207 this->LocalGenerator
->AddVisibilityPresetFlags(
208 flags
, this->GeneratorTarget
, language
);
209 this->LocalGenerator
->AddColorDiagnosticsFlags(flags
, language
);
211 // Append old-style preprocessor definition flags.
212 if (this->Makefile
->GetDefineFlags() != " ") {
213 this->LocalGenerator
->AppendFlags(flags
,
214 this->Makefile
->GetDefineFlags());
217 // Add target-specific flags.
218 this->LocalGenerator
->AddCompileOptions(flags
, this->GeneratorTarget
,
221 std::map
<std::string
, std::string
>::value_type
entry(language
, flags
);
222 i
= this->FlagsByLanguage
.insert(entry
).first
;
226 std::string
cmGhsMultiTargetGenerator::GetDefines(const std::string
& language
,
227 std::string
const& config
)
229 auto i
= this->DefinesByLanguage
.find(language
);
230 if (i
== this->DefinesByLanguage
.end()) {
231 std::set
<std::string
> defines
;
232 // Add preprocessor definitions for this target and configuration.
233 this->LocalGenerator
->GetTargetDefines(this->GeneratorTarget
, config
,
236 std::string definesString
;
237 this->LocalGenerator
->JoinDefines(defines
, definesString
, language
);
239 std::map
<std::string
, std::string
>::value_type
entry(language
,
241 i
= this->DefinesByLanguage
.insert(entry
).first
;
246 void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::ostream
& fout
,
248 const std::string
& language
)
250 auto flagsByLangI
= this->FlagsByLanguage
.find(language
);
251 if (flagsByLangI
!= this->FlagsByLanguage
.end()) {
252 if (!flagsByLangI
->second
.empty()) {
253 std::vector
<std::string
> ghsCompFlags
=
254 cmSystemTools::ParseArguments(flagsByLangI
->second
);
255 for (const std::string
& f
: ghsCompFlags
) {
256 fout
<< " " << f
<< '\n';
262 void cmGhsMultiTargetGenerator::WriteCompilerDefinitions(
263 std::ostream
& fout
, const std::string
& config
, const std::string
& language
)
265 std::vector
<std::string
> compileDefinitions
;
266 this->GeneratorTarget
->GetCompileDefinitions(compileDefinitions
, config
,
268 for (std::string
const& compileDefinition
: compileDefinitions
) {
269 fout
<< " -D" << compileDefinition
<< '\n';
273 void cmGhsMultiTargetGenerator::WriteIncludes(std::ostream
& fout
,
274 const std::string
& config
,
275 const std::string
& language
)
277 std::vector
<std::string
> includes
;
278 this->LocalGenerator
->GetIncludeDirectories(includes
, this->GeneratorTarget
,
281 for (std::string
const& include
: includes
) {
282 fout
<< " -I\"" << include
<< "\"\n";
286 void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream
& fout
,
287 std::string
const& config
)
289 if (this->TagType
== GhsMultiGpj::INTERGRITY_APPLICATION
) {
293 std::string linkLibraries
;
295 std::string linkFlags
;
296 std::string frameworkPath
;
297 std::string linkPath
;
299 std::unique_ptr
<cmLinkLineComputer
> linkLineComputer
=
300 this->GetGlobalGenerator()->CreateLinkLineComputer(
301 this->LocalGenerator
,
302 this->LocalGenerator
->GetStateSnapshot().GetDirectory());
304 this->LocalGenerator
->GetTargetFlags(
305 linkLineComputer
.get(), config
, linkLibraries
, flags
, linkFlags
,
306 frameworkPath
, linkPath
, this->GeneratorTarget
);
308 // write out link options
309 std::vector
<std::string
> lopts
= cmSystemTools::ParseArguments(linkFlags
);
310 for (const std::string
& l
: lopts
) {
311 fout
<< " " << l
<< '\n';
314 // write out link search paths
315 // must be quoted for paths that contain spaces
316 std::vector
<std::string
> lpath
= cmSystemTools::ParseArguments(linkPath
);
317 for (const std::string
& l
: lpath
) {
318 fout
<< " -L\"" << l
<< "\"\n";
321 // write out link libs
322 // must be quoted for filepaths that contains spaces
323 std::string cbd
= this->LocalGenerator
->GetCurrentBinaryDirectory();
325 std::vector
<std::string
> llibs
=
326 cmSystemTools::ParseArguments(linkLibraries
);
327 for (const std::string
& l
: llibs
) {
328 if (l
.compare(0, 2, "-l") == 0) {
329 fout
<< " \"" << l
<< "\"\n";
331 std::string rl
= cmSystemTools::CollapseFullPath(l
, cbd
);
332 fout
<< " -l\"" << rl
<< "\"\n";
337 void cmGhsMultiTargetGenerator::WriteBuildEvents(std::ostream
& fout
)
339 this->WriteBuildEventsHelper(fout
,
340 this->GeneratorTarget
->GetPreBuildCommands(),
341 std::string("prebuild"),
343 std::string("preexecShell")
345 std::string("preexec")
349 if (this->TagType
!= GhsMultiGpj::CUSTOM_TARGET
) {
350 this->WriteBuildEventsHelper(fout
,
351 this->GeneratorTarget
->GetPreLinkCommands(),
352 std::string("prelink"),
354 std::string("preexecShell")
356 std::string("preexec")
361 this->WriteBuildEventsHelper(fout
,
362 this->GeneratorTarget
->GetPostBuildCommands(),
363 std::string("postbuild"),
365 std::string("postexecShell")
367 std::string("postexec")
372 void cmGhsMultiTargetGenerator::WriteBuildEventsHelper(
373 std::ostream
& fout
, const std::vector
<cmCustomCommand
>& ccv
,
374 std::string
const& name
, std::string
const& cmd
)
378 std::string fext
= ".bat";
381 std::string fext
= ".sh";
382 std::string shell
= "/bin/sh ";
385 for (cmCustomCommand
const& cc
: ccv
) {
386 cmCustomCommandGenerator
ccg(cc
, this->ConfigName
, this->LocalGenerator
);
387 // Open the filestream for this custom command
389 cmStrCat(this->LocalGenerator
->GetCurrentBinaryDirectory(), '/',
390 this->LocalGenerator
->GetTargetDirectory(this->GeneratorTarget
),
391 '/', this->Name
, '_', name
, cmdcount
++, fext
);
393 cmGeneratedFileStream
f(fname
);
394 f
.SetCopyIfDifferent(true);
395 this->WriteCustomCommandsHelper(f
, ccg
);
397 if (this->TagType
!= GhsMultiGpj::CUSTOM_TARGET
) {
398 fout
<< " :" << cmd
<< "=\"" << shell
<< fname
<< "\"\n";
400 fout
<< fname
<< "\n :outputName=\"" << fname
<< ".rule\"\n";
402 for (const auto& byp
: ccg
.GetByproducts()) {
403 fout
<< " :extraOutputFile=\"" << byp
<< "\"\n";
408 void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
409 std::ostream
& fout
, cmCustomCommandGenerator
const& ccg
)
411 std::vector
<std::string
> cmdLines
;
413 // if the command specified a working directory use it.
414 std::string dir
= this->LocalGenerator
->GetCurrentBinaryDirectory();
415 std::string workingDir
= ccg
.GetWorkingDirectory();
416 if (!workingDir
.empty()) {
420 // Line to check for error between commands.
422 std::string check_error
= "if %errorlevel% neq 0 exit /b %errorlevel%";
424 std::string check_error
= "if [ $? -ne 0 ]; then exit 1; fi";
428 cmdLines
.push_back("@echo off");
430 // Echo the custom command's comment text.
431 if (cm::optional
<std::string
> comment
= ccg
.GetComment()) {
432 std::string escapedComment
= this->LocalGenerator
->EscapeForShell(
433 *comment
, ccg
.GetCC().GetEscapeAllowMakeVars());
434 std::string echocmd
= cmStrCat("echo ", escapedComment
);
435 cmdLines
.push_back(std::move(echocmd
));
438 // Switch to working directory
441 std::string cdStr
= "cd /D ";
443 std::string cdStr
= "cd ";
446 this->LocalGenerator
->ConvertToOutputFormat(dir
, cmOutputConverter::SHELL
);
447 cmdLines
.push_back(std::move(cdCmd
));
449 for (unsigned int c
= 0; c
< ccg
.GetNumberOfCommands(); ++c
) {
450 // Build the command line in a single string.
451 std::string cmd
= ccg
.GetCommand(c
);
453 // Use "call " before any invocations of .bat or .cmd files
454 // invoked as custom commands in the WindowsShell.
456 bool useCall
= false;
460 if (cmd
.size() > 4) {
461 suffix
= cmSystemTools::LowerCase(cmd
.substr(cmd
.size() - 4));
462 if (suffix
== ".bat" || suffix
== ".cmd") {
468 cmSystemTools::ReplaceString(cmd
, "/./", "/");
469 // Convert the command to a relative path only if the current
470 // working directory will be the start-output directory.
471 bool had_slash
= cmd
.find('/') != std::string::npos
;
472 if (workingDir
.empty()) {
473 cmd
= this->LocalGenerator
->MaybeRelativeToCurBinDir(cmd
);
475 bool has_slash
= cmd
.find('/') != std::string::npos
;
476 if (had_slash
&& !has_slash
) {
477 // This command was specified as a path to a file in the
478 // current directory. Add a leading "./" so it can run
479 // without the current directory being in the search path.
480 cmd
= cmStrCat("./", cmd
);
482 cmd
= this->LocalGenerator
->ConvertToOutputFormat(
483 cmd
, cmOutputConverter::SHELL
);
485 cmd
= cmStrCat("call ", cmd
);
487 ccg
.AppendArguments(c
, cmd
);
488 cmdLines
.push_back(std::move(cmd
));
492 // push back the custom commands
493 for (auto const& c
: cmdLines
) {
494 fout
<< c
<< '\n' << check_error
<< '\n';
498 void cmGhsMultiTargetGenerator::WriteSourceProperty(
499 std::ostream
& fout
, const cmSourceFile
* sf
, std::string
const& propName
,
500 std::string
const& propFlag
)
502 cmValue prop
= sf
->GetProperty(propName
);
504 cmList list
{ *prop
};
505 for (const std::string
& p
: list
) {
506 fout
<< " " << propFlag
<< p
<< '\n';
511 void cmGhsMultiTargetGenerator::WriteSources(std::ostream
& fout_proj
)
513 /* vector of all sources for this target */
514 std::vector
<cmSourceFile
*> sources
;
515 this->GeneratorTarget
->GetSourceFiles(sources
, this->ConfigName
);
517 /* vector of all groups defined for this target
518 * -- but the vector is not expanded with sub groups or in any useful order
520 std::vector
<cmSourceGroup
> sourceGroups
= this->Makefile
->GetSourceGroups();
522 /* for each source file assign it to its group */
523 std::map
<std::string
, std::vector
<cmSourceFile
*>> groupFiles
;
524 std::set
<std::string
> groupNames
;
525 for (cmSourceFile
* sf
: sources
) {
526 cmSourceGroup
* sourceGroup
=
527 this->Makefile
->FindSourceGroup(sf
->ResolveFullPath(), sourceGroups
);
528 std::string gn
= sourceGroup
->GetFullName();
529 groupFiles
[gn
].push_back(sf
);
530 groupNames
.insert(std::move(gn
));
533 /* list of known groups and the order they are displayed in a project file */
534 const std::vector
<std::string
> standardGroups
= {
535 "CMake Rules", "Header Files", "Source Files",
536 "Object Files", "Object Libraries", "Resources"
539 /* list of groups in the order they are displayed in a project file*/
540 std::vector
<std::string
> groupFilesList(groupFiles
.size());
542 /* put the groups in the order they should be listed
543 * - standard groups first, and then everything else
544 * in the order used by std::map.
547 for (const std::string
& gn
: standardGroups
) {
548 auto n
= groupNames
.find(gn
);
549 if (n
!= groupNames
.end()) {
550 groupFilesList
[i
] = *n
;
552 groupNames
.erase(gn
);
553 } else if (this->TagType
== GhsMultiGpj::CUSTOM_TARGET
&&
554 gn
== "CMake Rules") {
555 /* make sure that rules folder always exists in case of custom targets
556 * that have no custom commands except for pre or post build events.
558 groupFilesList
.resize(groupFilesList
.size() + 1);
559 groupFilesList
[i
] = gn
;
564 { /* catch-all group - is last item */
566 auto n
= groupNames
.find(gn
);
567 if (n
!= groupNames
.end()) {
568 groupFilesList
.back() = *n
;
569 groupNames
.erase(gn
);
573 for (const auto& n
: groupNames
) {
574 groupFilesList
[i
] = n
;
578 /* sort the files within each group */
579 for (auto& n
: groupFilesList
) {
580 std::sort(groupFiles
[n
].begin(), groupFiles
[n
].end(),
581 [](cmSourceFile
* l
, cmSourceFile
* r
) {
582 return l
->ResolveFullPath() < r
->ResolveFullPath();
586 /* list of open project files */
587 std::vector
<cmGeneratedFileStream
*> gfiles
;
589 /* write files into the proper project file
590 * -- groups go into main project file
591 * unless NO_SOURCE_GROUP_FILE property or variable is set.
593 for (auto& sg
: groupFilesList
) {
595 bool useProjectFile
=
596 this->GeneratorTarget
->GetProperty("GHS_NO_SOURCE_GROUP_FILE").IsOn() ||
597 this->Makefile
->IsOn("CMAKE_GHS_NO_SOURCE_GROUP_FILE");
598 if (useProjectFile
|| sg
.empty()) {
601 // Open the filestream in copy-if-different mode.
602 std::string gname
= sg
;
603 cmsys::SystemTools::ReplaceString(gname
, "\\", "_");
605 cmStrCat(gname
, cmGlobalGhsMultiGenerator::FILE_EXTENSION
);
606 std::string fpath
= cmStrCat(
607 this->LocalGenerator
->GetCurrentBinaryDirectory(), '/',
608 this->LocalGenerator
->GetTargetDirectory(this->GeneratorTarget
), '/',
610 cmGeneratedFileStream
* f
= new cmGeneratedFileStream(fpath
);
611 f
->SetCopyIfDifferent(true);
614 this->GetGlobalGenerator()->WriteFileHeader(*f
);
615 GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT
, *f
);
616 fout_proj
<< lpath
<< " ";
617 GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT
, fout_proj
);
620 if (useProjectFile
) {
622 *fout
<< "{comment} Others" << '\n';
624 *fout
<< "{comment} " << sg
<< '\n';
626 } else if (sg
.empty()) {
627 *fout
<< "{comment} Others\n";
630 if (sg
!= "CMake Rules") {
631 /* output rule for each source file */
632 for (const cmSourceFile
* si
: groupFiles
[sg
]) {
634 // Convert filename to native system
635 // WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on
636 // windows when opening some files from the search window.
637 std::string
fname(si
->GetFullPath());
638 cmSystemTools::ConvertToOutputSlashes(fname
);
640 /* For custom targets list any associated sources,
641 * comment out source code to prevent it from being
642 * compiled when processing this target.
643 * Otherwise, comment out any custom command (main) dependencies that
644 * are listed as source files to prevent them from being considered
648 if ((this->TagType
== GhsMultiGpj::CUSTOM_TARGET
&&
649 !si
->GetLanguage().empty()) ||
650 si
->GetCustomCommand()) {
651 comment
= "{comment} ";
655 *fout
<< comment
<< fname
<< WriteObjectLangOverride(si
) << '\n';
657 this->WriteSourceProperty(*fout
, si
, "INCLUDE_DIRECTORIES", "-I");
658 this->WriteSourceProperty(*fout
, si
, "COMPILE_DEFINITIONS", "-D");
659 this->WriteSourceProperty(*fout
, si
, "COMPILE_OPTIONS", "");
661 /* to avoid clutter in the GUI only print out the objectName if it
662 * has been renamed */
663 std::string objectName
= this->GeneratorTarget
->GetObjectName(si
);
664 if (!objectName
.empty() &&
665 this->GeneratorTarget
->HasExplicitObjectName(si
)) {
666 *fout
<< " -o " << objectName
<< '\n';
671 std::vector
<cmSourceFile
const*> customCommands
;
672 if (this->ComputeCustomCommandOrder(customCommands
)) {
673 std::string message
= "The custom commands for target [" +
674 this->GeneratorTarget
->GetName() + "] had a cycle.\n";
675 cmSystemTools::Error(message
);
677 /* Custom targets do not have a dependency on SOURCES files.
678 * Therefore the dependency list may include SOURCES files after the
679 * custom target. Because nothing can depend on the custom target just
680 * move it to the last item.
682 for (auto sf
= customCommands
.begin(); sf
!= customCommands
.end();
684 if (((*sf
)->GetLocation()).GetName() == this->Name
+ ".rule") {
685 std::rotate(sf
, sf
+ 1, customCommands
.end());
691 std::string fext
= ".bat";
693 std::string fext
= ".sh";
695 for (auto& sf
: customCommands
) {
696 const cmCustomCommand
* cc
= sf
->GetCustomCommand();
697 cmCustomCommandGenerator
ccg(*cc
, this->ConfigName
,
698 this->LocalGenerator
);
700 // Open the filestream for this custom command
701 std::string fname
= cmStrCat(
702 this->LocalGenerator
->GetCurrentBinaryDirectory(), '/',
703 this->LocalGenerator
->GetTargetDirectory(this->GeneratorTarget
),
704 '/', this->Name
, "_cc", cmdcount
++, '_',
705 (sf
->GetLocation()).GetName(), fext
);
707 cmGeneratedFileStream
f(fname
);
708 f
.SetCopyIfDifferent(true);
709 this->WriteCustomCommandsHelper(f
, ccg
);
711 this->WriteCustomCommandLine(*fout
, fname
, ccg
);
714 if (this->TagType
== GhsMultiGpj::CUSTOM_TARGET
) {
715 this->WriteBuildEvents(*fout
);
720 for (cmGeneratedFileStream
* f
: gfiles
) {
725 void cmGhsMultiTargetGenerator::WriteCustomCommandLine(
726 std::ostream
& fout
, std::string
& fname
, cmCustomCommandGenerator
const& ccg
)
728 /* NOTE: Customization Files are not well documented. Testing showed
729 * that ":outputName=file" can only be used once per script. The
730 * script will only run if ":outputName=file" is missing or just run
731 * once if ":outputName=file" is not specified. If there are
732 * multiple outputs then the script needs to be listed multiple times
733 * for each output. Otherwise it won't rerun the script if one of
734 * the outputs is manually deleted.
736 bool specifyExtra
= true;
737 for (const auto& out
: ccg
.GetOutputs()) {
738 fout
<< fname
<< '\n';
739 fout
<< " :outputName=\"" << out
<< "\"\n";
741 for (const auto& byp
: ccg
.GetByproducts()) {
742 fout
<< " :extraOutputFile=\"" << byp
<< "\"\n";
744 for (const auto& dep
: ccg
.GetDepends()) {
745 fout
<< " :depends=\"" << dep
<< "\"\n";
747 specifyExtra
= false;
752 std::string
cmGhsMultiTargetGenerator::WriteObjectLangOverride(
753 const cmSourceFile
* sourceFile
)
756 cmValue rawLangProp
= sourceFile
->GetProperty("LANGUAGE");
758 ret
= cmStrCat(" [", *rawLangProp
, "]");
764 bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()
766 if (cmValue p
= this->GeneratorTarget
->GetProperty("ghs_integrity_app")) {
769 std::vector
<cmSourceFile
*> sources
;
770 this->GeneratorTarget
->GetSourceFiles(sources
, this->ConfigName
);
771 return std::any_of(sources
.begin(), sources
.end(),
772 [](cmSourceFile
const* sf
) -> bool {
773 return "int" == sf
->GetExtension();
777 bool cmGhsMultiTargetGenerator::ComputeCustomCommandOrder(
778 std::vector
<cmSourceFile
const*>& order
)
780 std::set
<cmSourceFile
const*> temp
;
781 std::set
<cmSourceFile
const*> perm
;
783 // Collect all custom commands for this target
784 std::vector
<cmSourceFile
const*> customCommands
;
785 this->GeneratorTarget
->GetCustomCommands(customCommands
, this->ConfigName
);
787 for (cmSourceFile
const* si
: customCommands
) {
788 bool r
= this->VisitCustomCommand(temp
, perm
, order
, si
);
796 bool cmGhsMultiTargetGenerator::VisitCustomCommand(
797 std::set
<cmSourceFile
const*>& temp
, std::set
<cmSourceFile
const*>& perm
,
798 std::vector
<cmSourceFile
const*>& order
, cmSourceFile
const* si
)
800 /* check if permanent mark is set*/
801 if (perm
.find(si
) == perm
.end()) {
802 /* set temporary mark; check if revisit*/
803 if (temp
.insert(si
).second
) {
804 for (const auto& di
: si
->GetCustomCommand()->GetDepends()) {
805 cmSourceFile
const* sf
=
806 this->GeneratorTarget
->GetLocalGenerator()->GetSourceFileWithOutput(
808 /* if sf exists then visit */
809 if (sf
&& this->VisitCustomCommand(temp
, perm
, order
, sf
)) {
813 /* mark as complete; insert into beginning of list*/
818 /* revisiting item - not a DAG */
821 /* already complete */