resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmCPluginAPI.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 /*
4    this file contains the implementation of the C API to CMake. Generally
5    these routines just manipulate arguments and then call the associated
6    methods on the CMake classes. */
7
8 #include "cmCPluginAPI.h"
9
10 #include <cstdlib>
11
12 #include "cmExecutionStatus.h"
13 #include "cmGlobalGenerator.h"
14 #include "cmMakefile.h"
15 #include "cmSourceFile.h"
16 #include "cmState.h"
17 #include "cmVersion.h"
18
19 #ifdef __QNX__
20 #  include <malloc.h> /* for malloc/free on QNX */
21 #endif
22
23 extern "C" {
24
25 static void CCONV* cmGetClientData(void* info)
26 {
27   return ((cmLoadedCommandInfo*)info)->ClientData;
28 }
29
30 static void CCONV cmSetClientData(void* info, void* cd)
31 {
32   ((cmLoadedCommandInfo*)info)->ClientData = cd;
33 }
34
35 static void CCONV cmSetError(void* info, const char* err)
36 {
37   if (((cmLoadedCommandInfo*)info)->Error) {
38     free(((cmLoadedCommandInfo*)info)->Error);
39   }
40   ((cmLoadedCommandInfo*)info)->Error = strdup(err);
41 }
42
43 static unsigned int CCONV cmGetCacheMajorVersion(void* arg)
44 {
45   cmMakefile* mf = static_cast<cmMakefile*>(arg);
46   cmState* state = mf->GetState();
47   return state->GetCacheMajorVersion();
48 }
49 static unsigned int CCONV cmGetCacheMinorVersion(void* arg)
50 {
51   cmMakefile* mf = static_cast<cmMakefile*>(arg);
52   cmState* state = mf->GetState();
53   return state->GetCacheMinorVersion();
54 }
55
56 static unsigned int CCONV cmGetMajorVersion(void*)
57 {
58   return cmVersion::GetMajorVersion();
59 }
60
61 static unsigned int CCONV cmGetMinorVersion(void*)
62 {
63   return cmVersion::GetMinorVersion();
64 }
65
66 static void CCONV cmAddDefinition(void* arg, const char* name,
67                                   const char* value)
68 {
69   if (value) {
70     cmMakefile* mf = static_cast<cmMakefile*>(arg);
71     mf->AddDefinition(name, value);
72   }
73 }
74
75 /* Add a definition to this makefile and the global cmake cache. */
76 static void CCONV cmAddCacheDefinition(void* arg, const char* name,
77                                        const char* value, const char* doc,
78                                        int type)
79 {
80   cmMakefile* mf = static_cast<cmMakefile*>(arg);
81
82   switch (type) {
83     case CM_CACHE_BOOL:
84       mf->AddCacheDefinition(name, value, doc, cmStateEnums::BOOL);
85       break;
86     case CM_CACHE_PATH:
87       mf->AddCacheDefinition(name, value, doc, cmStateEnums::PATH);
88       break;
89     case CM_CACHE_FILEPATH:
90       mf->AddCacheDefinition(name, value, doc, cmStateEnums::FILEPATH);
91       break;
92     case CM_CACHE_STRING:
93       mf->AddCacheDefinition(name, value, doc, cmStateEnums::STRING);
94       break;
95     case CM_CACHE_INTERNAL:
96       mf->AddCacheDefinition(name, value, doc, cmStateEnums::INTERNAL);
97       break;
98     case CM_CACHE_STATIC:
99       mf->AddCacheDefinition(name, value, doc, cmStateEnums::STATIC);
100       break;
101   }
102 }
103
104 static const char* CCONV cmGetProjectName(void* arg)
105 {
106   cmMakefile* mf = static_cast<cmMakefile*>(arg);
107   static std::string name;
108   name = mf->GetStateSnapshot().GetProjectName();
109   return name.c_str();
110 }
111
112 static const char* CCONV cmGetHomeDirectory(void* arg)
113 {
114   cmMakefile* mf = static_cast<cmMakefile*>(arg);
115   return mf->GetHomeDirectory().c_str();
116 }
117 static const char* CCONV cmGetHomeOutputDirectory(void* arg)
118 {
119   cmMakefile* mf = static_cast<cmMakefile*>(arg);
120   return mf->GetHomeOutputDirectory().c_str();
121 }
122 static const char* CCONV cmGetStartDirectory(void* arg)
123 {
124   cmMakefile* mf = static_cast<cmMakefile*>(arg);
125   return mf->GetCurrentSourceDirectory().c_str();
126 }
127 static const char* CCONV cmGetStartOutputDirectory(void* arg)
128 {
129   cmMakefile* mf = static_cast<cmMakefile*>(arg);
130   return mf->GetCurrentBinaryDirectory().c_str();
131 }
132 static const char* CCONV cmGetCurrentDirectory(void* arg)
133 {
134   cmMakefile* mf = static_cast<cmMakefile*>(arg);
135   return mf->GetCurrentSourceDirectory().c_str();
136 }
137 static const char* CCONV cmGetCurrentOutputDirectory(void* arg)
138 {
139   cmMakefile* mf = static_cast<cmMakefile*>(arg);
140   return mf->GetCurrentBinaryDirectory().c_str();
141 }
142 static const char* CCONV cmGetDefinition(void* arg, const char* def)
143 {
144   cmMakefile* mf = static_cast<cmMakefile*>(arg);
145   return mf->GetDefinition(def).GetCStr();
146 }
147
148 static int CCONV cmIsOn(void* arg, const char* name)
149 {
150   cmMakefile* mf = static_cast<cmMakefile*>(arg);
151   return static_cast<int>(mf->IsOn(name));
152 }
153
154 /** Check if a command exists. */
155 static int CCONV cmCommandExists(void* arg, const char* name)
156 {
157   cmMakefile* mf = static_cast<cmMakefile*>(arg);
158   return static_cast<int>(mf->GetState()->GetCommand(name) ? 1 : 0);
159 }
160
161 static void CCONV cmAddDefineFlag(void* arg, const char* definition)
162 {
163   cmMakefile* mf = static_cast<cmMakefile*>(arg);
164   mf->AddDefineFlag(definition);
165 }
166
167 static void CCONV cmAddLinkDirectoryForTarget(void* arg, const char* tgt,
168                                               const char* d)
169 {
170   cmMakefile* mf = static_cast<cmMakefile*>(arg);
171   cmTarget* t = mf->FindLocalNonAliasTarget(tgt);
172   if (!t) {
173     cmSystemTools::Error(
174       "Attempt to add link directories to non-existent target: " +
175       std::string(tgt) + " for directory " + std::string(d));
176     return;
177   }
178   t->InsertLinkDirectory(BT<std::string>(d, mf->GetBacktrace()));
179 }
180
181 static void CCONV cmAddExecutable(void* arg, const char* exename, int numSrcs,
182                                   const char** srcs, int win32)
183 {
184   cmMakefile* mf = static_cast<cmMakefile*>(arg);
185   std::vector<std::string> srcs2;
186   int i;
187   for (i = 0; i < numSrcs; ++i) {
188     srcs2.emplace_back(srcs[i]);
189   }
190   cmTarget* tg = mf->AddExecutable(exename, srcs2);
191   if (win32) {
192     tg->SetProperty("WIN32_EXECUTABLE", "ON");
193   }
194 }
195
196 static void CCONV cmAddUtilityCommand(void* arg, const char* utilityName,
197                                       const char* command,
198                                       const char* arguments, int all,
199                                       int numDepends, const char** depends,
200                                       int, const char**)
201 {
202   // Get the makefile instance.  Perform an extra variable expansion
203   // now because the API caller expects it.
204   cmMakefile* mf = static_cast<cmMakefile*>(arg);
205
206   // Construct the command line for the command.
207   cmCustomCommandLine commandLine;
208   std::string expand = command;
209   commandLine.push_back(mf->ExpandVariablesInString(expand));
210   if (arguments && arguments[0]) {
211     // TODO: Parse arguments!
212     expand = arguments;
213     commandLine.push_back(mf->ExpandVariablesInString(expand));
214   }
215   cmCustomCommandLines commandLines;
216   commandLines.push_back(commandLine);
217
218   // Accumulate the list of dependencies.
219   std::vector<std::string> depends2;
220   for (int i = 0; i < numDepends; ++i) {
221     expand = depends[i];
222     depends2.push_back(mf->ExpandVariablesInString(expand));
223   }
224
225   // Pass the call to the makefile instance.
226   auto cc = cm::make_unique<cmCustomCommand>();
227   cc->SetDepends(depends2);
228   cc->SetCommandLines(commandLines);
229   mf->AddUtilityCommand(utilityName, !all, std::move(cc));
230 }
231
232 static void CCONV cmAddCustomCommand(void* arg, const char* source,
233                                      const char* command, int numArgs,
234                                      const char** args, int numDepends,
235                                      const char** depends, int numOutputs,
236                                      const char** outputs, const char* target)
237 {
238   // Get the makefile instance.  Perform an extra variable expansion
239   // now because the API caller expects it.
240   cmMakefile* mf = static_cast<cmMakefile*>(arg);
241
242   // Construct the command line for the command.
243   cmCustomCommandLine commandLine;
244   std::string expand = command;
245   commandLine.push_back(mf->ExpandVariablesInString(expand));
246   for (int i = 0; i < numArgs; ++i) {
247     expand = args[i];
248     commandLine.push_back(mf->ExpandVariablesInString(expand));
249   }
250   cmCustomCommandLines commandLines;
251   commandLines.push_back(commandLine);
252
253   // Accumulate the list of dependencies.
254   std::vector<std::string> depends2;
255   for (int i = 0; i < numDepends; ++i) {
256     expand = depends[i];
257     depends2.push_back(mf->ExpandVariablesInString(expand));
258   }
259
260   // Accumulate the list of outputs.
261   std::vector<std::string> outputs2;
262   for (int i = 0; i < numOutputs; ++i) {
263     expand = outputs[i];
264     outputs2.push_back(mf->ExpandVariablesInString(expand));
265   }
266
267   // Pass the call to the makefile instance.
268   const char* no_comment = nullptr;
269   mf->AddCustomCommandOldStyle(target, outputs2, depends2, source,
270                                commandLines, no_comment);
271 }
272
273 static void CCONV cmAddCustomCommandToOutput(void* arg, const char* output,
274                                              const char* command, int numArgs,
275                                              const char** args,
276                                              const char* main_dependency,
277                                              int numDepends,
278                                              const char** depends)
279 {
280   // Get the makefile instance.  Perform an extra variable expansion
281   // now because the API caller expects it.
282   cmMakefile* mf = static_cast<cmMakefile*>(arg);
283
284   // Construct the command line for the command.
285   cmCustomCommandLine commandLine;
286   std::string expand = command;
287   commandLine.push_back(mf->ExpandVariablesInString(expand));
288   for (int i = 0; i < numArgs; ++i) {
289     expand = args[i];
290     commandLine.push_back(mf->ExpandVariablesInString(expand));
291   }
292   cmCustomCommandLines commandLines;
293   commandLines.push_back(commandLine);
294
295   // Accumulate the list of dependencies.
296   std::vector<std::string> depends2;
297   for (int i = 0; i < numDepends; ++i) {
298     expand = depends[i];
299     depends2.push_back(mf->ExpandVariablesInString(expand));
300   }
301
302   // Pass the call to the makefile instance.
303   auto cc = cm::make_unique<cmCustomCommand>();
304   cc->SetOutputs(output);
305   cc->SetMainDependency(main_dependency);
306   cc->SetDepends(depends2);
307   cc->SetCommandLines(commandLines);
308   mf->AddCustomCommandToOutput(std::move(cc));
309 }
310
311 static void CCONV cmAddCustomCommandToTarget(void* arg, const char* target,
312                                              const char* command, int numArgs,
313                                              const char** args,
314                                              int commandType)
315 {
316   // Get the makefile instance.
317   cmMakefile* mf = static_cast<cmMakefile*>(arg);
318
319   // Construct the command line for the command.  Perform an extra
320   // variable expansion now because the API caller expects it.
321   cmCustomCommandLine commandLine;
322   std::string expand = command;
323   commandLine.push_back(mf->ExpandVariablesInString(expand));
324   for (int i = 0; i < numArgs; ++i) {
325     expand = args[i];
326     commandLine.push_back(mf->ExpandVariablesInString(expand));
327   }
328   cmCustomCommandLines commandLines;
329   commandLines.push_back(commandLine);
330
331   // Select the command type.
332   cmCustomCommandType cctype = cmCustomCommandType::POST_BUILD;
333   switch (commandType) {
334     case CM_PRE_BUILD:
335       cctype = cmCustomCommandType::PRE_BUILD;
336       break;
337     case CM_PRE_LINK:
338       cctype = cmCustomCommandType::PRE_LINK;
339       break;
340     case CM_POST_BUILD:
341       cctype = cmCustomCommandType::POST_BUILD;
342       break;
343   }
344
345   // Pass the call to the makefile instance.
346   auto cc = cm::make_unique<cmCustomCommand>();
347   cc->SetCommandLines(commandLines);
348   mf->AddCustomCommandToTarget(target, cctype, std::move(cc));
349 }
350
351 static void addLinkLibrary(cmMakefile* mf, std::string const& target,
352                            std::string const& lib, cmTargetLinkLibraryType llt)
353 {
354   cmTarget* t = mf->FindLocalNonAliasTarget(target);
355   if (!t) {
356     std::ostringstream e;
357     e << "Attempt to add link library \"" << lib << "\" to target \"" << target
358       << "\" which is not built in this directory.";
359     mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
360     return;
361   }
362
363   cmTarget* tgt = mf->GetGlobalGenerator()->FindTarget(lib);
364   if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) &&
365       (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) &&
366       (tgt->GetType() != cmStateEnums::INTERFACE_LIBRARY) &&
367       !tgt->IsExecutableWithExports()) {
368     std::ostringstream e;
369     e << "Target \"" << lib << "\" of type "
370       << cmState::GetTargetTypeName(tgt->GetType())
371       << " may not be linked into another target.  "
372       << "One may link only to STATIC or SHARED libraries, or "
373       << "to executables with the ENABLE_EXPORTS property set.";
374     mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
375   }
376
377   t->AddLinkLibrary(*mf, lib, llt);
378 }
379
380 static void CCONV cmAddLinkLibraryForTarget(void* arg, const char* tgt,
381                                             const char* value, int libtype)
382 {
383   cmMakefile* mf = static_cast<cmMakefile*>(arg);
384
385   switch (libtype) {
386     case CM_LIBRARY_GENERAL:
387       addLinkLibrary(mf, tgt, value, GENERAL_LibraryType);
388       break;
389     case CM_LIBRARY_DEBUG:
390       addLinkLibrary(mf, tgt, value, DEBUG_LibraryType);
391       break;
392     case CM_LIBRARY_OPTIMIZED:
393       addLinkLibrary(mf, tgt, value, OPTIMIZED_LibraryType);
394       break;
395   }
396 }
397
398 static void CCONV cmAddLibrary(void* arg, const char* libname, int shared,
399                                int numSrcs, const char** srcs)
400 {
401   cmMakefile* mf = static_cast<cmMakefile*>(arg);
402   std::vector<std::string> srcs2;
403   int i;
404   for (i = 0; i < numSrcs; ++i) {
405     srcs2.emplace_back(srcs[i]);
406   }
407   mf->AddLibrary(
408     libname,
409     (shared ? cmStateEnums::SHARED_LIBRARY : cmStateEnums::STATIC_LIBRARY),
410     srcs2);
411 }
412
413 static char CCONV* cmExpandVariablesInString(void* arg, const char* source,
414                                              int escapeQuotes, int atOnly)
415 {
416   cmMakefile* mf = static_cast<cmMakefile*>(arg);
417   std::string barf = source;
418   std::string const& result =
419     mf->ExpandVariablesInString(barf, escapeQuotes != 0, atOnly != 0);
420   return strdup(result.c_str());
421 }
422
423 static int CCONV cmExecuteCommand(void* arg, const char* name, int numArgs,
424                                   const char** args)
425 {
426   cmMakefile* mf = static_cast<cmMakefile*>(arg);
427
428   std::vector<cmListFileArgument> lffArgs;
429   lffArgs.reserve(numArgs);
430   for (int i = 0; i < numArgs; ++i) {
431     // Assume all arguments are quoted.
432     lffArgs.emplace_back(args[i], cmListFileArgument::Quoted, 0);
433   }
434
435   cmListFileFunction lff{ name, 0, 0, std::move(lffArgs) };
436   cmExecutionStatus status(*mf);
437   return mf->ExecuteCommand(lff, status);
438 }
439
440 static void CCONV cmExpandSourceListArguments(void* arg, int numArgs,
441                                               const char** args, int* resArgc,
442                                               char*** resArgv,
443                                               unsigned int startArgumentIndex)
444 {
445   (void)arg;
446   (void)startArgumentIndex;
447   std::vector<std::string> result;
448   int i;
449   for (i = 0; i < numArgs; ++i) {
450     result.emplace_back(args[i]);
451   }
452   int resargc = static_cast<int>(result.size());
453   char** resargv = nullptr;
454   if (resargc) {
455     resargv = (char**)malloc(resargc * sizeof(char*));
456   }
457   for (i = 0; i < resargc; ++i) {
458     resargv[i] = strdup(result[i].c_str());
459   }
460   *resArgc = resargc;
461   *resArgv = resargv;
462 }
463
464 static void CCONV cmFreeArguments(int argc, char** argv)
465 {
466   int i;
467   for (i = 0; i < argc; ++i) {
468     free(argv[i]);
469   }
470   free(argv);
471 }
472
473 static int CCONV cmGetTotalArgumentSize(int argc, char** argv)
474 {
475   int i;
476   int result = 0;
477   for (i = 0; i < argc; ++i) {
478     if (argv[i]) {
479       result = result + static_cast<int>(strlen(argv[i]));
480     }
481   }
482   return result;
483 }
484
485 // Source file proxy object to support the old cmSourceFile/cmMakefile
486 // API for source files.
487 struct cmCPluginAPISourceFile
488 {
489   cmSourceFile* RealSourceFile = nullptr;
490   std::string SourceName;
491   std::string SourceExtension;
492   std::string FullPath;
493   std::vector<std::string> Depends;
494   cmPropertyMap Properties;
495 };
496
497 // Keep a map from real cmSourceFile instances stored in a makefile to
498 // the CPluginAPI proxy source file.
499 using cmCPluginAPISourceFileMap =
500   std::map<cmSourceFile*, std::unique_ptr<cmCPluginAPISourceFile>>;
501 static cmCPluginAPISourceFileMap cmCPluginAPISourceFiles;
502
503 static void* CCONV cmCreateSourceFile()
504 {
505   return new cmCPluginAPISourceFile;
506 }
507
508 static void* CCONV cmCreateNewSourceFile(void*)
509 {
510   return new cmCPluginAPISourceFile;
511 }
512
513 static void CCONV cmDestroySourceFile(void* arg)
514 {
515   cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
516   // Only delete if it was created by cmCreateSourceFile or
517   // cmCreateNewSourceFile and is therefore not in the map.
518   if (!sf->RealSourceFile) {
519     delete sf;
520   }
521 }
522
523 static void CCONV* cmGetSource(void* arg, const char* name)
524 {
525   cmMakefile* mf = static_cast<cmMakefile*>(arg);
526   if (cmSourceFile* rsf = mf->GetSource(name)) {
527     // Lookup the proxy source file object for this source.
528     auto i = cmCPluginAPISourceFiles.find(rsf);
529     if (i == cmCPluginAPISourceFiles.end()) {
530       // Create a proxy source file object for this source.
531       auto sf = cm::make_unique<cmCPluginAPISourceFile>();
532       sf->RealSourceFile = rsf;
533       sf->FullPath = rsf->ResolveFullPath();
534       sf->SourceName =
535         cmSystemTools::GetFilenameWithoutLastExtension(sf->FullPath);
536       sf->SourceExtension =
537         cmSystemTools::GetFilenameLastExtension(sf->FullPath);
538
539       // Store the proxy in the map so it can be re-used and deleted later.
540       i = cmCPluginAPISourceFiles.emplace(rsf, std::move(sf)).first;
541     }
542     return i->second.get();
543   }
544   return nullptr;
545 }
546
547 static void* CCONV cmAddSource(void* arg, void* arg2)
548 {
549   cmMakefile* mf = static_cast<cmMakefile*>(arg);
550   cmCPluginAPISourceFile* osf = static_cast<cmCPluginAPISourceFile*>(arg2);
551   if (osf->FullPath.empty()) {
552     return nullptr;
553   }
554
555   // Create the real cmSourceFile instance and copy over saved information.
556   cmSourceFile* rsf = mf->GetOrCreateSource(osf->FullPath);
557   rsf->SetProperties(osf->Properties);
558   // In case the properties contain the GENERATED property,
559   // mark the real cmSourceFile as generated.
560   if (rsf->GetIsGenerated()) {
561     rsf->MarkAsGenerated();
562   }
563   for (std::string const& d : osf->Depends) {
564     rsf->AddDepend(d);
565   }
566
567   // Create the proxy for the real source file.
568   auto sf = cm::make_unique<cmCPluginAPISourceFile>();
569   sf->RealSourceFile = rsf;
570   sf->FullPath = osf->FullPath;
571   sf->SourceName = osf->SourceName;
572   sf->SourceExtension = osf->SourceExtension;
573
574   // Store the proxy in the map so it can be re-used and deleted later.
575   auto* value = sf.get();
576   cmCPluginAPISourceFiles[rsf] = std::move(sf);
577   return value;
578 }
579
580 static const char* CCONV cmSourceFileGetSourceName(void* arg)
581 {
582   cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
583   return sf->SourceName.c_str();
584 }
585
586 static const char* CCONV cmSourceFileGetFullPath(void* arg)
587 {
588   cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
589   return sf->FullPath.c_str();
590 }
591
592 static const char* CCONV cmSourceFileGetProperty(void* arg, const char* prop)
593 {
594   cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
595   if (cmSourceFile* rsf = sf->RealSourceFile) {
596     return rsf->GetProperty(prop).GetCStr();
597   }
598   if (!strcmp(prop, "LOCATION")) {
599     return sf->FullPath.c_str();
600   }
601   return sf->Properties.GetPropertyValue(prop).GetCStr();
602 }
603
604 static int CCONV cmSourceFileGetPropertyAsBool(void* arg, const char* prop)
605 {
606   cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
607   if (cmSourceFile* rsf = sf->RealSourceFile) {
608     return rsf->GetPropertyAsBool(prop) ? 1 : 0;
609   }
610   return cmIsOn(cmSourceFileGetProperty(arg, prop)) ? 1 : 0;
611 }
612
613 static void CCONV cmSourceFileSetProperty(void* arg, const char* prop,
614                                           const char* value)
615 {
616   cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
617   if (cmSourceFile* rsf = sf->RealSourceFile) {
618     rsf->SetProperty(prop, value);
619   } else if (prop) {
620     if (!value) {
621       value = "NOTFOUND";
622     }
623     sf->Properties.SetProperty(prop, value);
624   }
625 }
626
627 static void CCONV cmSourceFileAddDepend(void* arg, const char* depend)
628 {
629   cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
630   if (cmSourceFile* rsf = sf->RealSourceFile) {
631     rsf->AddDepend(depend);
632   } else {
633     sf->Depends.emplace_back(depend);
634   }
635 }
636
637 static void CCONV cmSourceFileSetName(void* arg, const char* name,
638                                       const char* dir, int numSourceExtensions,
639                                       const char** sourceExtensions,
640                                       int numHeaderExtensions,
641                                       const char** headerExtensions)
642 {
643   cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
644   if (sf->RealSourceFile) {
645     // SetName is allowed only on temporary source files created by
646     // the command for building and passing to AddSource.
647     return;
648   }
649   std::vector<std::string> sourceExts;
650   std::vector<std::string> headerExts;
651   int i;
652   for (i = 0; i < numSourceExtensions; ++i) {
653     sourceExts.emplace_back(sourceExtensions[i]);
654   }
655   for (i = 0; i < numHeaderExtensions; ++i) {
656     headerExts.emplace_back(headerExtensions[i]);
657   }
658
659   // Save the original name given.
660   sf->SourceName = name;
661
662   // Convert the name to a full path in case the given name is a
663   // relative path.
664   std::string pathname = cmSystemTools::CollapseFullPath(name, dir);
665
666   // First try and see whether the listed file can be found
667   // as is without extensions added on.
668   std::string hname = pathname;
669   if (cmSystemTools::FileExists(hname)) {
670     sf->SourceName = cmSystemTools::GetFilenamePath(name);
671     if (!sf->SourceName.empty()) {
672       sf->SourceName += "/";
673     }
674     sf->SourceName += cmSystemTools::GetFilenameWithoutLastExtension(name);
675     std::string::size_type pos = hname.rfind('.');
676     if (pos != std::string::npos) {
677       sf->SourceExtension = hname.substr(pos + 1, hname.size() - pos);
678       if (cmSystemTools::FileIsFullPath(name)) {
679         std::string::size_type pos2 = hname.rfind('/');
680         if (pos2 != std::string::npos) {
681           sf->SourceName = hname.substr(pos2 + 1, pos - pos2 - 1);
682         }
683       }
684     }
685
686     sf->FullPath = hname;
687     return;
688   }
689
690   // Next, try the various source extensions
691   for (std::string const& ext : sourceExts) {
692     hname = cmStrCat(pathname, '.', ext);
693     if (cmSystemTools::FileExists(hname)) {
694       sf->SourceExtension = ext;
695       sf->FullPath = hname;
696       return;
697     }
698   }
699
700   // Finally, try the various header extensions
701   for (std::string const& ext : headerExts) {
702     hname = cmStrCat(pathname, '.', ext);
703     if (cmSystemTools::FileExists(hname)) {
704       sf->SourceExtension = ext;
705       sf->FullPath = hname;
706       return;
707     }
708   }
709
710   std::ostringstream e;
711   e << "Cannot find source file \"" << pathname << "\"";
712   e << "\n\nTried extensions";
713   for (std::string const& ext : sourceExts) {
714     e << " ." << ext;
715   }
716   for (std::string const& ext : headerExts) {
717     e << " ." << ext;
718   }
719   cmSystemTools::Error(e.str());
720 }
721
722 static void CCONV cmSourceFileSetName2(void* arg, const char* name,
723                                        const char* dir, const char* ext,
724                                        int headerFileOnly)
725 {
726   cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
727   if (sf->RealSourceFile) {
728     // SetName is allowed only on temporary source files created by
729     // the command for building and passing to AddSource.
730     return;
731   }
732
733   // Implement the old SetName method code here.
734   if (headerFileOnly) {
735     sf->Properties.SetProperty("HEADER_FILE_ONLY", "1");
736   }
737   sf->SourceName = name;
738   std::string fname = sf->SourceName;
739   if (cmNonempty(ext)) {
740     fname += ".";
741     fname += ext;
742   }
743   sf->FullPath = cmSystemTools::CollapseFullPath(fname, dir);
744   cmSystemTools::ConvertToUnixSlashes(sf->FullPath);
745   sf->SourceExtension = ext;
746 }
747
748 static char* CCONV cmGetFilenameWithoutExtension(const char* name)
749 {
750   std::string sres = cmSystemTools::GetFilenameWithoutExtension(name);
751   return strdup(sres.c_str());
752 }
753
754 static char* CCONV cmGetFilenamePath(const char* name)
755 {
756   std::string sres = cmSystemTools::GetFilenamePath(name);
757   return strdup(sres.c_str());
758 }
759
760 static char* CCONV cmCapitalized(const char* name)
761 {
762   std::string sres = cmSystemTools::Capitalized(name);
763   return strdup(sres.c_str());
764 }
765
766 static void CCONV cmCopyFileIfDifferent(const char* name1, const char* name2)
767 {
768   cmSystemTools::CopyFileIfDifferent(name1, name2);
769 }
770
771 static void CCONV cmRemoveFile(const char* name)
772 {
773   cmSystemTools::RemoveFile(name);
774 }
775
776 static void CCONV cmDisplayStatus(void* arg, const char* message)
777 {
778   cmMakefile* mf = static_cast<cmMakefile*>(arg);
779   mf->DisplayStatus(message, -1);
780 }
781
782 static void CCONV cmFree(void* data)
783 {
784   free(data);
785 }
786
787 static void CCONV DefineSourceFileProperty(void* arg, const char* name,
788                                            const char* briefDocs,
789                                            const char* longDocs, int chained)
790 {
791   cmMakefile* mf = static_cast<cmMakefile*>(arg);
792   mf->GetState()->DefineProperty(name, cmProperty::SOURCE_FILE,
793                                  briefDocs ? briefDocs : "",
794                                  longDocs ? longDocs : "", chained != 0);
795 }
796
797 } // close the extern "C" scope
798
799 static cmCAPI cmStaticCAPI = {
800   cmGetClientData,
801   cmGetTotalArgumentSize,
802   cmFreeArguments,
803   cmSetClientData,
804   cmSetError,
805   cmAddCacheDefinition,
806   cmAddCustomCommand,
807   cmAddDefineFlag,
808   cmAddDefinition,
809   cmAddExecutable,
810   cmAddLibrary,
811   cmAddLinkDirectoryForTarget,
812   cmAddLinkLibraryForTarget,
813   cmAddUtilityCommand,
814   cmCommandExists,
815   cmExecuteCommand,
816   cmExpandSourceListArguments,
817   cmExpandVariablesInString,
818   cmGetCacheMajorVersion,
819   cmGetCacheMinorVersion,
820   cmGetCurrentDirectory,
821   cmGetCurrentOutputDirectory,
822   cmGetDefinition,
823   cmGetHomeDirectory,
824   cmGetHomeOutputDirectory,
825   cmGetMajorVersion,
826   cmGetMinorVersion,
827   cmGetProjectName,
828   cmGetStartDirectory,
829   cmGetStartOutputDirectory,
830   cmIsOn,
831
832   cmAddSource,
833   cmCreateSourceFile,
834   cmDestroySourceFile,
835   cmGetSource,
836   cmSourceFileAddDepend,
837   cmSourceFileGetProperty,
838   cmSourceFileGetPropertyAsBool,
839   cmSourceFileGetSourceName,
840   cmSourceFileGetFullPath,
841   cmSourceFileSetName,
842   cmSourceFileSetName2,
843   cmSourceFileSetProperty,
844
845   cmCapitalized,
846   cmCopyFileIfDifferent,
847   cmGetFilenameWithoutExtension,
848   cmGetFilenamePath,
849   cmRemoveFile,
850   cmFree,
851
852   cmAddCustomCommandToOutput,
853   cmAddCustomCommandToTarget,
854   cmDisplayStatus,
855   cmCreateNewSourceFile,
856   DefineSourceFileProperty,
857 };