b1d37a6ffd99c5aec98440b2aa7811d818378d10
[platform/upstream/cmake.git] / Source / cmCoreTryCompile.cxx
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 "cmCoreTryCompile.h"
4
5 #include <cstdio>
6 #include <cstring>
7 #include <set>
8 #include <sstream>
9 #include <utility>
10
11 #include <cm/string_view>
12 #include <cmext/string_view>
13
14 #include "cmsys/Directory.hxx"
15
16 #include "cmExportTryCompileFileGenerator.h"
17 #include "cmGlobalGenerator.h"
18 #include "cmMakefile.h"
19 #include "cmMessageType.h"
20 #include "cmOutputConverter.h"
21 #include "cmPolicies.h"
22 #include "cmState.h"
23 #include "cmStringAlgorithms.h"
24 #include "cmSystemTools.h"
25 #include "cmTarget.h"
26 #include "cmValue.h"
27 #include "cmVersion.h"
28 #include "cmake.h"
29
30 namespace {
31 class LanguageStandardState
32 {
33 public:
34   LanguageStandardState(std::string&& lang)
35     : StandardFlag(lang + "_STANDARD")
36     , RequiredFlag(lang + "_STANDARD_REQUIRED")
37     , ExtensionFlag(lang + "_EXTENSIONS")
38   {
39   }
40
41   void Enabled(bool isEnabled) { this->IsEnabled = isEnabled; }
42
43   bool UpdateIfMatches(std::vector<std::string> const& argv, size_t& index)
44   {
45     bool updated = false;
46     if (argv[index] == this->StandardFlag) {
47       this->DidStandard = true;
48       this->StandardValue = argv[++index];
49       updated = true;
50     } else if (argv[index] == this->RequiredFlag) {
51       this->DidStandardRequired = true;
52       this->RequiredValue = argv[++index];
53       updated = true;
54     } else if (argv[index] == this->ExtensionFlag) {
55       this->DidExtensions = true;
56       this->ExtensionValue = argv[++index];
57       updated = true;
58     }
59     return updated;
60   }
61
62   bool Validate(cmMakefile* const makefile) const
63   {
64     if (this->DidStandard) {
65       makefile->IssueMessage(
66         MessageType::FATAL_ERROR,
67         cmStrCat(this->StandardFlag,
68                  " allowed only in source file signature."));
69       return false;
70     }
71     if (this->DidStandardRequired) {
72       makefile->IssueMessage(
73         MessageType::FATAL_ERROR,
74         cmStrCat(this->RequiredFlag,
75                  " allowed only in source file signature."));
76       return false;
77     }
78     if (this->DidExtensions) {
79       makefile->IssueMessage(
80         MessageType::FATAL_ERROR,
81         cmStrCat(this->ExtensionFlag,
82                  " allowed only in source file signature."));
83       return false;
84     }
85
86     return true;
87   }
88
89   bool DidNone() const
90   {
91     return !this->DidStandard && !this->DidStandardRequired &&
92       !this->DidExtensions;
93   }
94
95   void LoadUnsetPropertyValues(cmMakefile* const makefile, bool honorStandard,
96                                bool warnCMP0067,
97                                std::vector<std::string>& warnCMP0067Variables)
98   {
99     if (!this->IsEnabled) {
100       return;
101     }
102
103     auto lookupStdVar = [&](std::string const& var) -> std::string {
104       std::string value = makefile->GetSafeDefinition(var);
105       if (warnCMP0067 && !value.empty()) {
106         value.clear();
107         warnCMP0067Variables.emplace_back(var);
108       }
109       return value;
110     };
111
112     if (honorStandard || warnCMP0067) {
113       if (!this->DidStandard) {
114         this->StandardValue =
115           lookupStdVar(cmStrCat("CMAKE_", this->StandardFlag));
116       }
117       if (!this->DidStandardRequired) {
118         this->RequiredValue =
119           lookupStdVar(cmStrCat("CMAKE_", this->RequiredFlag));
120       }
121       if (!this->DidExtensions) {
122         this->ExtensionValue =
123           lookupStdVar(cmStrCat("CMAKE_", this->ExtensionFlag));
124       }
125     }
126   }
127
128   void WriteProperties(FILE* fout, std::string const& targetName) const
129   {
130     if (!this->IsEnabled) {
131       return;
132     }
133
134     auto writeProp = [&](std::string const& prop, std::string const& value) {
135       fprintf(fout, "set_property(TARGET %s PROPERTY %s %s)\n",
136               targetName.c_str(),
137               cmOutputConverter::EscapeForCMake(prop).c_str(),
138               cmOutputConverter::EscapeForCMake(value).c_str());
139     };
140
141     if (!this->StandardValue.empty()) {
142       writeProp(this->StandardFlag, this->StandardValue);
143     }
144     if (!this->RequiredValue.empty()) {
145       writeProp(this->RequiredFlag, this->RequiredValue);
146     }
147     if (!this->ExtensionValue.empty()) {
148       writeProp(this->ExtensionFlag, this->ExtensionValue);
149     }
150   }
151
152 private:
153   bool IsEnabled = false;
154   bool DidStandard = false;
155   bool DidStandardRequired = false;
156   bool DidExtensions = false;
157
158   std::string StandardFlag;
159   std::string RequiredFlag;
160   std::string ExtensionFlag;
161
162   std::string StandardValue;
163   std::string RequiredValue;
164   std::string ExtensionValue;
165 };
166
167 constexpr size_t lang_property_start = 0;
168 constexpr size_t lang_property_size = 4;
169 constexpr size_t pie_property_start = 4;
170 constexpr size_t pie_property_size = 2;
171 #define SETUP_LANGUAGE(name, lang)                                            \
172   static const std::string name[lang_property_size + pie_property_size + 1] = \
173     { "CMAKE_" #lang "_COMPILER_EXTERNAL_TOOLCHAIN",                          \
174       "CMAKE_" #lang "_COMPILER_TARGET",                                      \
175       "CMAKE_" #lang "_LINK_NO_PIE_SUPPORTED",                                \
176       "CMAKE_" #lang "_PIE_SUPPORTED", "" }
177
178 // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
179 SETUP_LANGUAGE(c_properties, C);
180 // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
181 SETUP_LANGUAGE(cxx_properties, CXX);
182
183 // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
184 SETUP_LANGUAGE(cuda_properties, CUDA);
185 // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
186 SETUP_LANGUAGE(fortran_properties, Fortran);
187 // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
188 SETUP_LANGUAGE(hip_properties, HIP);
189 // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
190 SETUP_LANGUAGE(objc_properties, OBJC);
191 // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
192 SETUP_LANGUAGE(objcxx_properties, OBJCXX);
193 // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
194 SETUP_LANGUAGE(ispc_properties, ISPC);
195 // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
196 SETUP_LANGUAGE(swift_properties, Swift);
197 #undef SETUP_LANGUAGE
198
199 std::string const kCMAKE_CUDA_ARCHITECTURES = "CMAKE_CUDA_ARCHITECTURES";
200 std::string const kCMAKE_CUDA_RUNTIME_LIBRARY = "CMAKE_CUDA_RUNTIME_LIBRARY";
201 std::string const kCMAKE_ENABLE_EXPORTS = "CMAKE_ENABLE_EXPORTS";
202 std::string const kCMAKE_HIP_ARCHITECTURES = "CMAKE_HIP_ARCHITECTURES";
203 std::string const kCMAKE_HIP_RUNTIME_LIBRARY = "CMAKE_HIP_RUNTIME_LIBRARY";
204 std::string const kCMAKE_ISPC_INSTRUCTION_SETS = "CMAKE_ISPC_INSTRUCTION_SETS";
205 std::string const kCMAKE_ISPC_HEADER_SUFFIX = "CMAKE_ISPC_HEADER_SUFFIX";
206 std::string const kCMAKE_LINK_SEARCH_END_STATIC =
207   "CMAKE_LINK_SEARCH_END_STATIC";
208 std::string const kCMAKE_LINK_SEARCH_START_STATIC =
209   "CMAKE_LINK_SEARCH_START_STATIC";
210 std::string const kCMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT =
211   "CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT";
212 std::string const kCMAKE_OSX_ARCHITECTURES = "CMAKE_OSX_ARCHITECTURES";
213 std::string const kCMAKE_OSX_DEPLOYMENT_TARGET = "CMAKE_OSX_DEPLOYMENT_TARGET";
214 std::string const kCMAKE_OSX_SYSROOT = "CMAKE_OSX_SYSROOT";
215 std::string const kCMAKE_APPLE_ARCH_SYSROOTS = "CMAKE_APPLE_ARCH_SYSROOTS";
216 std::string const kCMAKE_POSITION_INDEPENDENT_CODE =
217   "CMAKE_POSITION_INDEPENDENT_CODE";
218 std::string const kCMAKE_SYSROOT = "CMAKE_SYSROOT";
219 std::string const kCMAKE_SYSROOT_COMPILE = "CMAKE_SYSROOT_COMPILE";
220 std::string const kCMAKE_SYSROOT_LINK = "CMAKE_SYSROOT_LINK";
221 std::string const kCMAKE_ARMClang_CMP0123 = "CMAKE_ARMClang_CMP0123";
222 std::string const kCMAKE_TRY_COMPILE_OSX_ARCHITECTURES =
223   "CMAKE_TRY_COMPILE_OSX_ARCHITECTURES";
224 std::string const kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES =
225   "CMAKE_TRY_COMPILE_PLATFORM_VARIABLES";
226 std::string const kCMAKE_WARN_DEPRECATED = "CMAKE_WARN_DEPRECATED";
227 std::string const kCMAKE_WATCOM_RUNTIME_LIBRARY_DEFAULT =
228   "CMAKE_WATCOM_RUNTIME_LIBRARY_DEFAULT";
229
230 /* GHS Multi platform variables */
231 std::set<std::string> const ghs_platform_vars{
232   "GHS_TARGET_PLATFORM", "GHS_PRIMARY_TARGET", "GHS_TOOLSET_ROOT",
233   "GHS_OS_ROOT",         "GHS_OS_DIR",         "GHS_BSP_NAME",
234   "GHS_OS_DIR_OPTION"
235 };
236 }
237
238 int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
239                                      bool isTryRun)
240 {
241   this->BinaryDirectory = argv[1];
242   this->OutputFile.clear();
243   // which signature were we called with ?
244   this->SrcFileSignature = true;
245
246   cmStateEnums::TargetType targetType = cmStateEnums::EXECUTABLE;
247   cmValue tt = this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_TARGET_TYPE");
248   if (!isTryRun && cmNonempty(tt)) {
249     if (*tt == cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE)) {
250       targetType = cmStateEnums::EXECUTABLE;
251     } else if (*tt ==
252                cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY)) {
253       targetType = cmStateEnums::STATIC_LIBRARY;
254     } else {
255       this->Makefile->IssueMessage(
256         MessageType::FATAL_ERROR,
257         cmStrCat("Invalid value '", *tt,
258                  "' for CMAKE_TRY_COMPILE_TARGET_TYPE.  Only '",
259                  cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE),
260                  "' and '",
261                  cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY),
262                  "' are allowed."));
263       return -1;
264     }
265   }
266
267   std::string sourceDirectory = argv[2];
268   std::string projectName;
269   std::string targetName;
270   std::vector<std::string> cmakeFlags(1, "CMAKE_FLAGS"); // fake argv[0]
271   std::vector<std::string> compileDefs;
272   std::string cmakeInternal;
273   std::string outputVariable;
274   std::string copyFile;
275   std::string copyFileError;
276   LanguageStandardState cState("C");
277   LanguageStandardState cudaState("CUDA");
278   LanguageStandardState cxxState("CXX");
279   LanguageStandardState hipState("HIP");
280   LanguageStandardState objcState("OBJC");
281   LanguageStandardState objcxxState("OBJCXX");
282   std::vector<std::string> targets;
283   std::vector<std::string> linkOptions;
284   std::string libsToLink = " ";
285   bool useOldLinkLibs = true;
286   char targetNameBuf[64];
287   bool didOutputVariable = false;
288   bool didCopyFile = false;
289   bool didCopyFileError = false;
290   bool useSources = argv[2] == "SOURCES";
291   std::vector<std::string> sources;
292
293   enum Doing
294   {
295     DoingNone,
296     DoingCMakeFlags,
297     DoingCompileDefinitions,
298     DoingLinkOptions,
299     DoingLinkLibraries,
300     DoingOutputVariable,
301     DoingCopyFile,
302     DoingCopyFileError,
303     DoingSources,
304     DoingCMakeInternal
305   };
306   Doing doing = useSources ? DoingSources : DoingNone;
307   for (size_t i = 3; i < argv.size(); ++i) {
308     if (argv[i] == "CMAKE_FLAGS") {
309       doing = DoingCMakeFlags;
310     } else if (argv[i] == "COMPILE_DEFINITIONS") {
311       doing = DoingCompileDefinitions;
312     } else if (argv[i] == "LINK_OPTIONS") {
313       doing = DoingLinkOptions;
314     } else if (argv[i] == "LINK_LIBRARIES") {
315       doing = DoingLinkLibraries;
316       useOldLinkLibs = false;
317     } else if (argv[i] == "OUTPUT_VARIABLE") {
318       doing = DoingOutputVariable;
319       didOutputVariable = true;
320     } else if (argv[i] == "COPY_FILE") {
321       doing = DoingCopyFile;
322       didCopyFile = true;
323     } else if (argv[i] == "COPY_FILE_ERROR") {
324       doing = DoingCopyFileError;
325       didCopyFileError = true;
326     } else if (cState.UpdateIfMatches(argv, i) ||
327                cxxState.UpdateIfMatches(argv, i) ||
328                cudaState.UpdateIfMatches(argv, i) ||
329                hipState.UpdateIfMatches(argv, i) ||
330                objcState.UpdateIfMatches(argv, i) ||
331                objcxxState.UpdateIfMatches(argv, i)) {
332       continue;
333     } else if (argv[i] == "__CMAKE_INTERNAL") {
334       doing = DoingCMakeInternal;
335     } else if (doing == DoingCMakeFlags) {
336       cmakeFlags.emplace_back(argv[i]);
337     } else if (doing == DoingCompileDefinitions) {
338       cmExpandList(argv[i], compileDefs);
339     } else if (doing == DoingLinkOptions) {
340       linkOptions.emplace_back(argv[i]);
341     } else if (doing == DoingLinkLibraries) {
342       libsToLink += "\"" + cmTrimWhitespace(argv[i]) + "\" ";
343       if (cmTarget* tgt = this->Makefile->FindTargetToUse(argv[i])) {
344         switch (tgt->GetType()) {
345           case cmStateEnums::SHARED_LIBRARY:
346           case cmStateEnums::STATIC_LIBRARY:
347           case cmStateEnums::INTERFACE_LIBRARY:
348           case cmStateEnums::UNKNOWN_LIBRARY:
349             break;
350           case cmStateEnums::EXECUTABLE:
351             if (tgt->IsExecutableWithExports()) {
352               break;
353             }
354             CM_FALLTHROUGH;
355           default:
356             this->Makefile->IssueMessage(
357               MessageType::FATAL_ERROR,
358               cmStrCat("Only libraries may be used as try_compile or try_run "
359                        "IMPORTED LINK_LIBRARIES.  Got ",
360                        tgt->GetName(), " of type ",
361                        cmState::GetTargetTypeName(tgt->GetType()), "."));
362             return -1;
363         }
364         if (tgt->IsImported()) {
365           targets.emplace_back(argv[i]);
366         }
367       }
368     } else if (doing == DoingOutputVariable) {
369       outputVariable = argv[i];
370       doing = DoingNone;
371     } else if (doing == DoingCopyFile) {
372       copyFile = argv[i];
373       doing = DoingNone;
374     } else if (doing == DoingCopyFileError) {
375       copyFileError = argv[i];
376       doing = DoingNone;
377     } else if (doing == DoingSources) {
378       sources.emplace_back(argv[i]);
379     } else if (doing == DoingCMakeInternal) {
380       cmakeInternal = argv[i];
381       doing = DoingNone;
382     } else if (i == 3) {
383       this->SrcFileSignature = false;
384       projectName = argv[i];
385     } else if (i == 4 && !this->SrcFileSignature) {
386       targetName = argv[i];
387     } else {
388       std::ostringstream m;
389       m << "try_compile given unknown argument \"" << argv[i] << "\".";
390       this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, m.str());
391     }
392   }
393
394   if (didCopyFile && copyFile.empty()) {
395     this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
396                                  "COPY_FILE must be followed by a file path");
397     return -1;
398   }
399
400   if (didCopyFileError && copyFileError.empty()) {
401     this->Makefile->IssueMessage(
402       MessageType::FATAL_ERROR,
403       "COPY_FILE_ERROR must be followed by a variable name");
404     return -1;
405   }
406
407   if (didCopyFileError && !didCopyFile) {
408     this->Makefile->IssueMessage(
409       MessageType::FATAL_ERROR,
410       "COPY_FILE_ERROR may be used only with COPY_FILE");
411     return -1;
412   }
413
414   if (didOutputVariable && outputVariable.empty()) {
415     this->Makefile->IssueMessage(
416       MessageType::FATAL_ERROR,
417       "OUTPUT_VARIABLE must be followed by a variable name");
418     return -1;
419   }
420
421   if (useSources && sources.empty()) {
422     this->Makefile->IssueMessage(
423       MessageType::FATAL_ERROR,
424       "SOURCES must be followed by at least one source file");
425     return -1;
426   }
427
428   if (!this->SrcFileSignature) {
429     if (!cState.Validate(this->Makefile)) {
430       return -1;
431     }
432     if (!cudaState.Validate(this->Makefile)) {
433       return -1;
434     }
435     if (!hipState.Validate(this->Makefile)) {
436       return -1;
437     }
438     if (!cxxState.Validate(this->Makefile)) {
439       return -1;
440     }
441     if (!objcState.Validate(this->Makefile)) {
442       return -1;
443     }
444     if (!objcxxState.Validate(this->Makefile)) {
445       return -1;
446     }
447   }
448
449   // compute the binary dir when TRY_COMPILE is called with a src file
450   // signature
451   if (this->SrcFileSignature) {
452     this->BinaryDirectory += "/CMakeFiles/CMakeTmp";
453   } else {
454     // only valid for srcfile signatures
455     if (!compileDefs.empty()) {
456       this->Makefile->IssueMessage(
457         MessageType::FATAL_ERROR,
458         "COMPILE_DEFINITIONS specified on a srcdir type TRY_COMPILE");
459       return -1;
460     }
461     if (!copyFile.empty()) {
462       this->Makefile->IssueMessage(
463         MessageType::FATAL_ERROR,
464         "COPY_FILE specified on a srcdir type TRY_COMPILE");
465       return -1;
466     }
467   }
468   // make sure the binary directory exists
469   cmSystemTools::MakeDirectory(this->BinaryDirectory);
470
471   // do not allow recursive try Compiles
472   if (this->BinaryDirectory == this->Makefile->GetHomeOutputDirectory()) {
473     std::ostringstream e;
474     e << "Attempt at a recursive or nested TRY_COMPILE in directory\n"
475       << "  " << this->BinaryDirectory << "\n";
476     this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
477     return -1;
478   }
479
480   std::string outFileName = this->BinaryDirectory + "/CMakeLists.txt";
481   // which signature are we using? If we are using var srcfile bindir
482   if (this->SrcFileSignature) {
483     // remove any CMakeCache.txt files so we will have a clean test
484     std::string ccFile = this->BinaryDirectory + "/CMakeCache.txt";
485     cmSystemTools::RemoveFile(ccFile);
486
487     // Choose sources.
488     if (!useSources) {
489       sources.emplace_back(argv[2]);
490     }
491
492     // Detect languages to enable.
493     cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
494     std::set<std::string> testLangs;
495     for (std::string const& si : sources) {
496       std::string ext = cmSystemTools::GetFilenameLastExtension(si);
497       std::string lang = gg->GetLanguageFromExtension(ext.c_str());
498       if (!lang.empty()) {
499         testLangs.insert(lang);
500       } else {
501         std::ostringstream err;
502         err << "Unknown extension \"" << ext << "\" for file\n"
503             << "  " << si << "\n"
504             << "try_compile() works only for enabled languages.  "
505             << "Currently these are:\n  ";
506         std::vector<std::string> langs;
507         gg->GetEnabledLanguages(langs);
508         err << cmJoin(langs, " ");
509         err << "\nSee project() command to enable other languages.";
510         this->Makefile->IssueMessage(MessageType::FATAL_ERROR, err.str());
511         return -1;
512       }
513     }
514
515     // when the only language is ISPC we know that the output
516     // type must by a static library
517     if (testLangs.size() == 1 && testLangs.count("ISPC") == 1) {
518       targetType = cmStateEnums::STATIC_LIBRARY;
519     }
520
521     std::string const tcConfig =
522       this->Makefile->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
523
524     // we need to create a directory and CMakeLists file etc...
525     // first create the directories
526     sourceDirectory = this->BinaryDirectory;
527
528     // now create a CMakeLists.txt file in that directory
529     FILE* fout = cmsys::SystemTools::Fopen(outFileName, "w");
530     if (!fout) {
531       std::ostringstream e;
532       /* clang-format off */
533       e << "Failed to open\n"
534         << "  " << outFileName << "\n"
535         << cmSystemTools::GetLastSystemError();
536       /* clang-format on */
537       this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
538       return -1;
539     }
540
541     cmValue def = this->Makefile->GetDefinition("CMAKE_MODULE_PATH");
542     fprintf(fout, "cmake_minimum_required(VERSION %u.%u.%u.%u)\n",
543             cmVersion::GetMajorVersion(), cmVersion::GetMinorVersion(),
544             cmVersion::GetPatchVersion(), cmVersion::GetTweakVersion());
545     if (def) {
546       fprintf(fout, "set(CMAKE_MODULE_PATH \"%s\")\n", def->c_str());
547     }
548
549     /* Set MSVC runtime library policy to match our selection.  */
550     if (cmValue msvcRuntimeLibraryDefault =
551           this->Makefile->GetDefinition(kCMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)) {
552       fprintf(fout, "cmake_policy(SET CMP0091 %s)\n",
553               !msvcRuntimeLibraryDefault->empty() ? "NEW" : "OLD");
554     }
555
556     /* Set Watcom runtime library policy to match our selection.  */
557     if (cmValue watcomRuntimeLibraryDefault = this->Makefile->GetDefinition(
558           kCMAKE_WATCOM_RUNTIME_LIBRARY_DEFAULT)) {
559       fprintf(fout, "cmake_policy(SET CMP0136 %s)\n",
560               !watcomRuntimeLibraryDefault->empty() ? "NEW" : "OLD");
561     }
562
563     /* Set CUDA architectures policy to match outer project.  */
564     if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0104) !=
565           cmPolicies::NEW &&
566         testLangs.find("CUDA") != testLangs.end() &&
567         this->Makefile->GetSafeDefinition(kCMAKE_CUDA_ARCHITECTURES).empty()) {
568       fprintf(fout, "cmake_policy(SET CMP0104 OLD)\n");
569     }
570
571     /* Set ARMClang cpu/arch policy to match outer project.  */
572     if (cmValue cmp0123 =
573           this->Makefile->GetDefinition(kCMAKE_ARMClang_CMP0123)) {
574       fprintf(fout, "cmake_policy(SET CMP0123 %s)\n",
575               *cmp0123 == "NEW"_s ? "NEW" : "OLD");
576     }
577
578     /* Set cache/normal variable policy to match outer project.
579        It may affect toolchain files.  */
580     if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0126) !=
581         cmPolicies::NEW) {
582       fprintf(fout, "cmake_policy(SET CMP0126 OLD)\n");
583     }
584
585     /* Set language extensions policy to match outer project.  */
586     if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0128) !=
587         cmPolicies::NEW) {
588       fprintf(fout, "cmake_policy(SET CMP0128 OLD)\n");
589     }
590
591     std::string projectLangs;
592     for (std::string const& li : testLangs) {
593       projectLangs += " " + li;
594       std::string rulesOverrideBase = "CMAKE_USER_MAKE_RULES_OVERRIDE";
595       std::string rulesOverrideLang = cmStrCat(rulesOverrideBase, "_", li);
596       if (cmValue rulesOverridePath =
597             this->Makefile->GetDefinition(rulesOverrideLang)) {
598         fprintf(fout, "set(%s \"%s\")\n", rulesOverrideLang.c_str(),
599                 rulesOverridePath->c_str());
600       } else if (cmValue rulesOverridePath2 =
601                    this->Makefile->GetDefinition(rulesOverrideBase)) {
602         fprintf(fout, "set(%s \"%s\")\n", rulesOverrideBase.c_str(),
603                 rulesOverridePath2->c_str());
604       }
605     }
606     fprintf(fout, "project(CMAKE_TRY_COMPILE%s)\n", projectLangs.c_str());
607     if (cmakeInternal == "ABI") {
608       // This is the ABI detection step, also used for implicit includes.
609       // Erase any include_directories() calls from the toolchain file so
610       // that we do not see them as implicit.  Our ABI detection source
611       // does not include any system headers anyway.
612       fprintf(fout,
613               "set_property(DIRECTORY PROPERTY INCLUDE_DIRECTORIES \"\")\n");
614     }
615     fprintf(fout, "set(CMAKE_VERBOSE_MAKEFILE 1)\n");
616     for (std::string const& li : testLangs) {
617       std::string langFlags = "CMAKE_" + li + "_FLAGS";
618       cmValue flags = this->Makefile->GetDefinition(langFlags);
619       fprintf(fout, "set(CMAKE_%s_FLAGS %s)\n", li.c_str(),
620               cmOutputConverter::EscapeForCMake(*flags).c_str());
621       fprintf(fout,
622               "set(CMAKE_%s_FLAGS \"${CMAKE_%s_FLAGS}"
623               " ${COMPILE_DEFINITIONS}\")\n",
624               li.c_str(), li.c_str());
625     }
626     switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0066)) {
627       case cmPolicies::WARN:
628         if (this->Makefile->PolicyOptionalWarningEnabled(
629               "CMAKE_POLICY_WARNING_CMP0066")) {
630           std::ostringstream w;
631           /* clang-format off */
632           w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0066) << "\n"
633             "For compatibility with older versions of CMake, try_compile "
634             "is not honoring caller config-specific compiler flags "
635             "(e.g. CMAKE_C_FLAGS_DEBUG) in the test project."
636             ;
637           /* clang-format on */
638           this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
639         }
640         CM_FALLTHROUGH;
641       case cmPolicies::OLD:
642         // OLD behavior is to do nothing.
643         break;
644       case cmPolicies::REQUIRED_IF_USED:
645       case cmPolicies::REQUIRED_ALWAYS:
646         this->Makefile->IssueMessage(
647           MessageType::FATAL_ERROR,
648           cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0066));
649         CM_FALLTHROUGH;
650       case cmPolicies::NEW: {
651         // NEW behavior is to pass config-specific compiler flags.
652         static std::string const cfgDefault = "DEBUG";
653         std::string const cfg =
654           !tcConfig.empty() ? cmSystemTools::UpperCase(tcConfig) : cfgDefault;
655         for (std::string const& li : testLangs) {
656           std::string const langFlagsCfg =
657             cmStrCat("CMAKE_", li, "_FLAGS_", cfg);
658           cmValue flagsCfg = this->Makefile->GetDefinition(langFlagsCfg);
659           fprintf(fout, "set(%s %s)\n", langFlagsCfg.c_str(),
660                   cmOutputConverter::EscapeForCMake(*flagsCfg).c_str());
661         }
662       } break;
663     }
664     switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0056)) {
665       case cmPolicies::WARN:
666         if (this->Makefile->PolicyOptionalWarningEnabled(
667               "CMAKE_POLICY_WARNING_CMP0056")) {
668           std::ostringstream w;
669           /* clang-format off */
670           w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0056) << "\n"
671             "For compatibility with older versions of CMake, try_compile "
672             "is not honoring caller link flags (e.g. CMAKE_EXE_LINKER_FLAGS) "
673             "in the test project."
674             ;
675           /* clang-format on */
676           this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
677         }
678         CM_FALLTHROUGH;
679       case cmPolicies::OLD:
680         // OLD behavior is to do nothing.
681         break;
682       case cmPolicies::REQUIRED_IF_USED:
683       case cmPolicies::REQUIRED_ALWAYS:
684         this->Makefile->IssueMessage(
685           MessageType::FATAL_ERROR,
686           cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0056));
687         CM_FALLTHROUGH;
688       case cmPolicies::NEW:
689         // NEW behavior is to pass linker flags.
690         {
691           cmValue exeLinkFlags =
692             this->Makefile->GetDefinition("CMAKE_EXE_LINKER_FLAGS");
693           fprintf(fout, "set(CMAKE_EXE_LINKER_FLAGS %s)\n",
694                   cmOutputConverter::EscapeForCMake(*exeLinkFlags).c_str());
695         }
696         break;
697     }
698     fprintf(fout,
699             "set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS}"
700             " ${EXE_LINKER_FLAGS}\")\n");
701     fprintf(fout, "include_directories(${INCLUDE_DIRECTORIES})\n");
702     fprintf(fout, "set(CMAKE_SUPPRESS_REGENERATION 1)\n");
703     fprintf(fout, "link_directories(${LINK_DIRECTORIES})\n");
704     // handle any compile flags we need to pass on
705     if (!compileDefs.empty()) {
706       // Pass using bracket arguments to preserve content.
707       fprintf(fout, "add_definitions([==[%s]==])\n",
708               cmJoin(compileDefs, "]==] [==[").c_str());
709     }
710
711     /* Use a random file name to avoid rapid creation and deletion
712        of the same executable name (some filesystems fail on that).  */
713     snprintf(targetNameBuf, sizeof(targetNameBuf), "cmTC_%05x",
714              cmSystemTools::RandomSeed() & 0xFFFFF);
715     targetName = targetNameBuf;
716
717     if (!targets.empty()) {
718       std::string fname = "/" + std::string(targetName) + "Targets.cmake";
719       cmExportTryCompileFileGenerator tcfg(gg, targets, this->Makefile,
720                                            testLangs);
721       tcfg.SetExportFile((this->BinaryDirectory + fname).c_str());
722       tcfg.SetConfig(tcConfig);
723
724       if (!tcfg.GenerateImportFile()) {
725         this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
726                                      "could not write export file.");
727         fclose(fout);
728         return -1;
729       }
730       fprintf(fout, "\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/%s\")\n\n",
731               fname.c_str());
732     }
733
734     /* Set the appropriate policy information for ENABLE_EXPORTS */
735     fprintf(fout, "cmake_policy(SET CMP0065 %s)\n",
736             this->Makefile->GetPolicyStatus(cmPolicies::CMP0065) ==
737                 cmPolicies::NEW
738               ? "NEW"
739               : "OLD");
740
741     /* Set the appropriate policy information for PIE link flags */
742     fprintf(fout, "cmake_policy(SET CMP0083 %s)\n",
743             this->Makefile->GetPolicyStatus(cmPolicies::CMP0083) ==
744                 cmPolicies::NEW
745               ? "NEW"
746               : "OLD");
747
748     // Workaround for -Wl,-headerpad_max_install_names issue until we can avoid
749     // adding that flag in the platform and compiler language files
750     fprintf(fout,
751             "include(\"${CMAKE_ROOT}/Modules/Internal/"
752             "HeaderpadWorkaround.cmake\")\n");
753
754     if (targetType == cmStateEnums::EXECUTABLE) {
755       /* Put the executable at a known location (for COPY_FILE).  */
756       fprintf(fout, "set(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"%s\")\n",
757               this->BinaryDirectory.c_str());
758       /* Create the actual executable.  */
759       fprintf(fout, "add_executable(%s", targetName.c_str());
760     } else // if (targetType == cmStateEnums::STATIC_LIBRARY)
761     {
762       /* Put the static library at a known location (for COPY_FILE).  */
763       fprintf(fout, "set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY \"%s\")\n",
764               this->BinaryDirectory.c_str());
765       /* Create the actual static library.  */
766       fprintf(fout, "add_library(%s STATIC", targetName.c_str());
767     }
768     for (std::string const& si : sources) {
769       fprintf(fout, " \"%s\"", si.c_str());
770
771       // Add dependencies on any non-temporary sources.
772       if (si.find("CMakeTmp") == std::string::npos) {
773         this->Makefile->AddCMakeDependFile(si);
774       }
775     }
776     fprintf(fout, ")\n");
777
778     cState.Enabled(testLangs.find("C") != testLangs.end());
779     cxxState.Enabled(testLangs.find("CXX") != testLangs.end());
780     cudaState.Enabled(testLangs.find("CUDA") != testLangs.end());
781     hipState.Enabled(testLangs.find("HIP") != testLangs.end());
782     objcState.Enabled(testLangs.find("OBJC") != testLangs.end());
783     objcxxState.Enabled(testLangs.find("OBJCXX") != testLangs.end());
784
785     bool warnCMP0067 = false;
786     bool honorStandard = true;
787
788     if (cState.DidNone() && cxxState.DidNone() && objcState.DidNone() &&
789         objcxxState.DidNone() && cudaState.DidNone() && hipState.DidNone()) {
790       switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0067)) {
791         case cmPolicies::WARN:
792           warnCMP0067 = this->Makefile->PolicyOptionalWarningEnabled(
793             "CMAKE_POLICY_WARNING_CMP0067");
794           CM_FALLTHROUGH;
795         case cmPolicies::OLD:
796           // OLD behavior is to not honor the language standard variables.
797           honorStandard = false;
798           break;
799         case cmPolicies::REQUIRED_IF_USED:
800         case cmPolicies::REQUIRED_ALWAYS:
801           this->Makefile->IssueMessage(
802             MessageType::FATAL_ERROR,
803             cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0067));
804           break;
805         case cmPolicies::NEW:
806           // NEW behavior is to honor the language standard variables.
807           // We already initialized honorStandard to true.
808           break;
809       }
810     }
811
812     std::vector<std::string> warnCMP0067Variables;
813
814     cState.LoadUnsetPropertyValues(this->Makefile, honorStandard, warnCMP0067,
815                                    warnCMP0067Variables);
816     cxxState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
817                                      warnCMP0067, warnCMP0067Variables);
818     cudaState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
819                                       warnCMP0067, warnCMP0067Variables);
820     hipState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
821                                      warnCMP0067, warnCMP0067Variables);
822     objcState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
823                                       warnCMP0067, warnCMP0067Variables);
824     objcxxState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
825                                         warnCMP0067, warnCMP0067Variables);
826
827     if (!warnCMP0067Variables.empty()) {
828       std::ostringstream w;
829       /* clang-format off */
830       w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0067) << "\n"
831         "For compatibility with older versions of CMake, try_compile "
832         "is not honoring language standard variables in the test project:\n"
833         ;
834       /* clang-format on */
835       for (std::string const& vi : warnCMP0067Variables) {
836         w << "  " << vi << "\n";
837       }
838       this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
839     }
840
841     cState.WriteProperties(fout, targetName);
842     cxxState.WriteProperties(fout, targetName);
843     cudaState.WriteProperties(fout, targetName);
844     hipState.WriteProperties(fout, targetName);
845     objcState.WriteProperties(fout, targetName);
846     objcxxState.WriteProperties(fout, targetName);
847
848     if (!linkOptions.empty()) {
849       std::vector<std::string> options;
850       options.reserve(linkOptions.size());
851       for (const auto& option : linkOptions) {
852         options.emplace_back(cmOutputConverter::EscapeForCMake(option));
853       }
854
855       if (targetType == cmStateEnums::STATIC_LIBRARY) {
856         fprintf(fout,
857                 "set_property(TARGET %s PROPERTY STATIC_LIBRARY_OPTIONS %s)\n",
858                 targetName.c_str(), cmJoin(options, " ").c_str());
859       } else {
860         fprintf(fout, "target_link_options(%s PRIVATE %s)\n",
861                 targetName.c_str(), cmJoin(options, " ").c_str());
862       }
863     }
864
865     if (useOldLinkLibs) {
866       fprintf(fout, "target_link_libraries(%s ${LINK_LIBRARIES})\n",
867               targetName.c_str());
868     } else {
869       fprintf(fout, "target_link_libraries(%s %s)\n", targetName.c_str(),
870               libsToLink.c_str());
871     }
872     fclose(fout);
873     projectName = "CMAKE_TRY_COMPILE";
874   }
875
876   // Forward a set of variables to the inner project cache.
877   if ((this->SrcFileSignature ||
878        this->Makefile->GetPolicyStatus(cmPolicies::CMP0137) ==
879          cmPolicies::NEW) &&
880       !this->Makefile->IsOn("CMAKE_TRY_COMPILE_NO_PLATFORM_VARIABLES")) {
881     std::set<std::string> vars;
882     vars.insert(&c_properties[lang_property_start],
883                 &c_properties[lang_property_start + lang_property_size]);
884     vars.insert(&cxx_properties[lang_property_start],
885                 &cxx_properties[lang_property_start + lang_property_size]);
886     vars.insert(&cuda_properties[lang_property_start],
887                 &cuda_properties[lang_property_start + lang_property_size]);
888     vars.insert(&fortran_properties[lang_property_start],
889                 &fortran_properties[lang_property_start + lang_property_size]);
890     vars.insert(&hip_properties[lang_property_start],
891                 &hip_properties[lang_property_start + lang_property_size]);
892     vars.insert(&objc_properties[lang_property_start],
893                 &objc_properties[lang_property_start + lang_property_size]);
894     vars.insert(&objcxx_properties[lang_property_start],
895                 &objcxx_properties[lang_property_start + lang_property_size]);
896     vars.insert(&ispc_properties[lang_property_start],
897                 &ispc_properties[lang_property_start + lang_property_size]);
898     vars.insert(&swift_properties[lang_property_start],
899                 &swift_properties[lang_property_start + lang_property_size]);
900     vars.insert(kCMAKE_CUDA_ARCHITECTURES);
901     vars.insert(kCMAKE_CUDA_RUNTIME_LIBRARY);
902     vars.insert(kCMAKE_ENABLE_EXPORTS);
903     vars.insert(kCMAKE_HIP_ARCHITECTURES);
904     vars.insert(kCMAKE_HIP_RUNTIME_LIBRARY);
905     vars.insert(kCMAKE_ISPC_INSTRUCTION_SETS);
906     vars.insert(kCMAKE_ISPC_HEADER_SUFFIX);
907     vars.insert(kCMAKE_LINK_SEARCH_END_STATIC);
908     vars.insert(kCMAKE_LINK_SEARCH_START_STATIC);
909     vars.insert(kCMAKE_OSX_ARCHITECTURES);
910     vars.insert(kCMAKE_OSX_DEPLOYMENT_TARGET);
911     vars.insert(kCMAKE_OSX_SYSROOT);
912     vars.insert(kCMAKE_APPLE_ARCH_SYSROOTS);
913     vars.insert(kCMAKE_POSITION_INDEPENDENT_CODE);
914     vars.insert(kCMAKE_SYSROOT);
915     vars.insert(kCMAKE_SYSROOT_COMPILE);
916     vars.insert(kCMAKE_SYSROOT_LINK);
917     vars.insert(kCMAKE_WARN_DEPRECATED);
918     vars.emplace("CMAKE_MSVC_RUNTIME_LIBRARY"_s);
919     vars.emplace("CMAKE_WATCOM_RUNTIME_LIBRARY"_s);
920
921     if (cmValue varListStr = this->Makefile->GetDefinition(
922           kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES)) {
923       std::vector<std::string> varList = cmExpandedList(*varListStr);
924       vars.insert(varList.begin(), varList.end());
925     }
926
927     if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0083) ==
928         cmPolicies::NEW) {
929       // To ensure full support of PIE, propagate cache variables
930       // driving the link options
931       vars.insert(&c_properties[pie_property_start],
932                   &c_properties[pie_property_start + pie_property_size]);
933       vars.insert(&cxx_properties[pie_property_start],
934                   &cxx_properties[pie_property_start + pie_property_size]);
935       vars.insert(&cuda_properties[pie_property_start],
936                   &cuda_properties[pie_property_start + pie_property_size]);
937       vars.insert(&fortran_properties[pie_property_start],
938                   &fortran_properties[pie_property_start + pie_property_size]);
939       vars.insert(&hip_properties[pie_property_start],
940                   &hip_properties[pie_property_start + pie_property_size]);
941       vars.insert(&objc_properties[pie_property_start],
942                   &objc_properties[pie_property_start + pie_property_size]);
943       vars.insert(&objcxx_properties[pie_property_start],
944                   &objcxx_properties[pie_property_start + pie_property_size]);
945       vars.insert(&ispc_properties[pie_property_start],
946                   &ispc_properties[pie_property_start + pie_property_size]);
947       vars.insert(&swift_properties[pie_property_start],
948                   &swift_properties[pie_property_start + pie_property_size]);
949     }
950
951     /* for the TRY_COMPILEs we want to be able to specify the architecture.
952        So the user can set CMAKE_OSX_ARCHITECTURES to i386;ppc and then set
953        CMAKE_TRY_COMPILE_OSX_ARCHITECTURES first to i386 and then to ppc to
954        have the tests run for each specific architecture. Since
955        cmLocalGenerator doesn't allow building for "the other"
956        architecture only via CMAKE_OSX_ARCHITECTURES.
957        */
958     if (cmValue tcArchs = this->Makefile->GetDefinition(
959           kCMAKE_TRY_COMPILE_OSX_ARCHITECTURES)) {
960       vars.erase(kCMAKE_OSX_ARCHITECTURES);
961       std::string flag = "-DCMAKE_OSX_ARCHITECTURES=" + *tcArchs;
962       cmakeFlags.emplace_back(std::move(flag));
963     }
964
965     for (std::string const& var : vars) {
966       if (cmValue val = this->Makefile->GetDefinition(var)) {
967         std::string flag = "-D" + var + "=" + *val;
968         cmakeFlags.emplace_back(std::move(flag));
969       }
970     }
971   }
972
973   if (this->Makefile->GetState()->UseGhsMultiIDE()) {
974     // Forward the GHS variables to the inner project cache.
975     for (std::string const& var : ghs_platform_vars) {
976       if (cmValue val = this->Makefile->GetDefinition(var)) {
977         std::string flag = "-D" + var + "=" + "'" + *val + "'";
978         cmakeFlags.emplace_back(std::move(flag));
979       }
980     }
981   }
982
983   bool erroroc = cmSystemTools::GetErrorOccurredFlag();
984   cmSystemTools::ResetErrorOccurredFlag();
985   std::string output;
986   // actually do the try compile now that everything is setup
987   int res = this->Makefile->TryCompile(
988     sourceDirectory, this->BinaryDirectory, projectName, targetName,
989     this->SrcFileSignature, cmake::NO_BUILD_PARALLEL_LEVEL, &cmakeFlags,
990     output);
991   if (erroroc) {
992     cmSystemTools::SetErrorOccurred();
993   }
994
995   // set the result var to the return value to indicate success or failure
996   this->Makefile->AddCacheDefinition(argv[0], (res == 0 ? "TRUE" : "FALSE"),
997                                      "Result of TRY_COMPILE",
998                                      cmStateEnums::INTERNAL);
999
1000   if (!outputVariable.empty()) {
1001     this->Makefile->AddDefinition(outputVariable, output);
1002   }
1003
1004   if (this->SrcFileSignature) {
1005     std::string copyFileErrorMessage;
1006     this->FindOutputFile(targetName, targetType);
1007
1008     if ((res == 0) && !copyFile.empty()) {
1009       if (this->OutputFile.empty() ||
1010           !cmSystemTools::CopyFileAlways(this->OutputFile, copyFile)) {
1011         std::ostringstream emsg;
1012         /* clang-format off */
1013         emsg << "Cannot copy output executable\n"
1014              << "  '" << this->OutputFile << "'\n"
1015              << "to destination specified by COPY_FILE:\n"
1016              << "  '" << copyFile << "'\n";
1017         /* clang-format on */
1018         if (!this->FindErrorMessage.empty()) {
1019           emsg << this->FindErrorMessage;
1020         }
1021         if (copyFileError.empty()) {
1022           this->Makefile->IssueMessage(MessageType::FATAL_ERROR, emsg.str());
1023           return -1;
1024         }
1025         copyFileErrorMessage = emsg.str();
1026       }
1027     }
1028
1029     if (!copyFileError.empty()) {
1030       this->Makefile->AddDefinition(copyFileError, copyFileErrorMessage);
1031     }
1032   }
1033   return res;
1034 }
1035
1036 void cmCoreTryCompile::CleanupFiles(std::string const& binDir)
1037 {
1038   if (binDir.empty()) {
1039     return;
1040   }
1041
1042   if (binDir.find("CMakeTmp") == std::string::npos) {
1043     cmSystemTools::Error(
1044       "TRY_COMPILE attempt to remove -rf directory that does not contain "
1045       "CMakeTmp:" +
1046       binDir);
1047     return;
1048   }
1049
1050   cmsys::Directory dir;
1051   dir.Load(binDir);
1052   std::set<std::string> deletedFiles;
1053   for (unsigned long i = 0; i < dir.GetNumberOfFiles(); ++i) {
1054     const char* fileName = dir.GetFile(i);
1055     if (strcmp(fileName, ".") != 0 && strcmp(fileName, "..") != 0 &&
1056         // Do not delete NFS temporary files.
1057         !cmHasPrefix(fileName, ".nfs")) {
1058       if (deletedFiles.insert(fileName).second) {
1059         std::string const fullPath =
1060           std::string(binDir).append("/").append(fileName);
1061         if (cmSystemTools::FileIsSymlink(fullPath)) {
1062           cmSystemTools::RemoveFile(fullPath);
1063         } else if (cmSystemTools::FileIsDirectory(fullPath)) {
1064           this->CleanupFiles(fullPath);
1065           cmSystemTools::RemoveADirectory(fullPath);
1066         } else {
1067 #ifdef _WIN32
1068           // Sometimes anti-virus software hangs on to new files so we
1069           // cannot delete them immediately.  Try a few times.
1070           cmSystemTools::WindowsFileRetry retry =
1071             cmSystemTools::GetWindowsFileRetry();
1072           cmsys::Status status;
1073           while (!((status = cmSystemTools::RemoveFile(fullPath))) &&
1074                  --retry.Count && cmSystemTools::FileExists(fullPath)) {
1075             cmSystemTools::Delay(retry.Delay);
1076           }
1077           if (retry.Count == 0)
1078 #else
1079           cmsys::Status status = cmSystemTools::RemoveFile(fullPath);
1080           if (!status)
1081 #endif
1082           {
1083             this->Makefile->IssueMessage(
1084               MessageType::FATAL_ERROR,
1085               cmStrCat("The file:\n  ", fullPath,
1086                        "\ncould not be removed:\n  ", status.GetString()));
1087           }
1088         }
1089       }
1090     }
1091   }
1092 }
1093
1094 void cmCoreTryCompile::FindOutputFile(const std::string& targetName,
1095                                       cmStateEnums::TargetType targetType)
1096 {
1097   this->FindErrorMessage.clear();
1098   this->OutputFile.clear();
1099   std::string tmpOutputFile = "/";
1100   if (targetType == cmStateEnums::EXECUTABLE) {
1101     tmpOutputFile += targetName;
1102     tmpOutputFile +=
1103       this->Makefile->GetSafeDefinition("CMAKE_EXECUTABLE_SUFFIX");
1104   } else // if (targetType == cmStateEnums::STATIC_LIBRARY)
1105   {
1106     tmpOutputFile +=
1107       this->Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX");
1108     tmpOutputFile += targetName;
1109     tmpOutputFile +=
1110       this->Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX");
1111   }
1112
1113   // a list of directories where to search for the compilation result
1114   // at first directly in the binary dir
1115   std::vector<std::string> searchDirs;
1116   searchDirs.emplace_back();
1117
1118   cmValue config =
1119     this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
1120   // if a config was specified try that first
1121   if (cmNonempty(config)) {
1122     std::string tmp = cmStrCat('/', *config);
1123     searchDirs.emplace_back(std::move(tmp));
1124   }
1125   searchDirs.emplace_back("/Debug");
1126 #if defined(__APPLE__)
1127   std::string app = "/" + targetName + ".app";
1128   if (cmNonempty(config)) {
1129     std::string tmp = cmStrCat('/', *config, app);
1130     searchDirs.emplace_back(std::move(tmp));
1131   }
1132   std::string tmp = "/Debug" + app;
1133   searchDirs.emplace_back(std::move(tmp));
1134   searchDirs.emplace_back(std::move(app));
1135 #endif
1136   searchDirs.emplace_back("/Development");
1137
1138   for (std::string const& sdir : searchDirs) {
1139     std::string command = cmStrCat(this->BinaryDirectory, sdir, tmpOutputFile);
1140     if (cmSystemTools::FileExists(command)) {
1141       this->OutputFile = cmSystemTools::CollapseFullPath(command);
1142       return;
1143     }
1144   }
1145
1146   std::ostringstream emsg;
1147   emsg << "Unable to find the executable at any of:\n";
1148   emsg << cmWrap("  " + this->BinaryDirectory, searchDirs, tmpOutputFile, "\n")
1149        << "\n";
1150   this->FindErrorMessage = emsg.str();
1151 }