CMake/Source/cmCPluginAPI.cxx

878 lines
26 KiB
C++
Raw Normal View History

Simplify CMake per-source license notices Per-source copyright/license notice headers that spell out copyright holder names and years are hard to maintain and often out-of-date or plain wrong. Precise contributor information is already maintained automatically by the version control tool. Ultimately it is the receiver of a file who is responsible for determining its licensing status, and per-source notices are merely a convenience. Therefore it is simpler and more accurate for each source to have a generic notice of the license name and references to more detailed information on copyright holders and full license terms. Our `Copyright.txt` file now contains a list of Contributors whose names appeared source-level copyright notices. It also references version control history for more precise information. Therefore we no longer need to spell out the list of Contributors in each source file notice. Replace CMake per-source copyright/license notice headers with a short description of the license and links to `Copyright.txt` and online information available from "https://cmake.org/licensing". The online URL also handles cases of modules being copied out of our source into other projects, so we can drop our notices about replacing links with full license text. Run the `Utilities/Scripts/filter-notices.bash` script to perform the majority of the replacements mechanically. Manually fix up shebang lines and trailing newlines in a few files. Manually update the notices in a few files that the script does not handle.
2016-09-27 19:01:08 +00:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
2006-03-10 18:06:26 +00:00
/*
2002-08-21 15:54:06 +00:00
this file contains the implementation of the C API to CMake. Generally
these routines just manipulate arguments and then call the associated
methods on the CMake classes. */
#include "cmCPluginAPI.h"
#include "cmExecutionStatus.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
2004-02-22 18:14:59 +00:00
#include "cmSourceFile.h"
#include "cmState.h"
#include "cmVersion.h"
2004-02-22 18:14:59 +00:00
#include <stdlib.h>
#ifdef __QNX__
#include <malloc.h> /* for malloc/free on QNX */
#endif
extern "C" {
2006-03-10 18:06:26 +00:00
void CCONV* cmGetClientData(void* info)
2002-08-21 15:54:06 +00:00
{
return ((cmLoadedCommandInfo*)info)->ClientData;
2002-08-21 15:54:06 +00:00
}
void CCONV cmSetClientData(void* info, void* cd)
2002-08-21 15:54:06 +00:00
{
((cmLoadedCommandInfo*)info)->ClientData = cd;
2002-08-21 15:54:06 +00:00
}
void CCONV cmSetError(void* info, const char* err)
2002-10-08 19:55:04 +00:00
{
if (((cmLoadedCommandInfo*)info)->Error) {
free(((cmLoadedCommandInfo*)info)->Error);
}
((cmLoadedCommandInfo*)info)->Error = strdup(err);
2002-10-08 19:55:04 +00:00
}
unsigned int CCONV cmGetCacheMajorVersion(void* arg)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
cmState* state = mf->GetState();
2015-10-10 12:34:26 +00:00
return state->GetCacheMajorVersion();
2002-08-21 15:54:06 +00:00
}
unsigned int CCONV cmGetCacheMinorVersion(void* arg)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
cmState* state = mf->GetState();
2015-10-10 12:34:26 +00:00
return state->GetCacheMinorVersion();
2002-08-21 15:54:06 +00:00
}
unsigned int CCONV cmGetMajorVersion(void*)
2002-08-21 15:54:06 +00:00
{
return cmVersion::GetMajorVersion();
2002-08-21 15:54:06 +00:00
}
unsigned int CCONV cmGetMinorVersion(void*)
2002-08-21 15:54:06 +00:00
{
return cmVersion::GetMinorVersion();
2002-08-21 15:54:06 +00:00
}
void CCONV cmAddDefinition(void* arg, const char* name, const char* value)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
mf->AddDefinition(name, value);
2002-08-21 15:54:06 +00:00
}
/* Add a definition to this makefile and the global cmake cache. */
void CCONV cmAddCacheDefinition(void* arg, const char* name, const char* value,
const char* doc, int type)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
2006-03-10 18:06:26 +00:00
switch (type) {
2002-08-21 15:54:06 +00:00
case CM_CACHE_BOOL:
mf->AddCacheDefinition(name, value, doc, cmStateEnums::BOOL);
2002-08-21 15:54:06 +00:00
break;
case CM_CACHE_PATH:
mf->AddCacheDefinition(name, value, doc, cmStateEnums::PATH);
2002-08-21 15:54:06 +00:00
break;
case CM_CACHE_FILEPATH:
mf->AddCacheDefinition(name, value, doc, cmStateEnums::FILEPATH);
2002-08-21 15:54:06 +00:00
break;
case CM_CACHE_STRING:
mf->AddCacheDefinition(name, value, doc, cmStateEnums::STRING);
2002-08-21 15:54:06 +00:00
break;
case CM_CACHE_INTERNAL:
mf->AddCacheDefinition(name, value, doc, cmStateEnums::INTERNAL);
2002-08-21 15:54:06 +00:00
break;
case CM_CACHE_STATIC:
mf->AddCacheDefinition(name, value, doc, cmStateEnums::STATIC);
2002-08-21 15:54:06 +00:00
break;
}
2002-08-21 15:54:06 +00:00
}
const char* CCONV cmGetProjectName(void* arg)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
static std::string name;
name = mf->GetStateSnapshot().GetProjectName();
return name.c_str();
2002-08-21 15:54:06 +00:00
}
const char* CCONV cmGetHomeDirectory(void* arg)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
2002-08-21 15:54:06 +00:00
return mf->GetHomeDirectory();
}
const char* CCONV cmGetHomeOutputDirectory(void* arg)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
2002-08-21 15:54:06 +00:00
return mf->GetHomeOutputDirectory();
}
const char* CCONV cmGetStartDirectory(void* arg)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
return mf->GetCurrentSourceDirectory();
2002-08-21 15:54:06 +00:00
}
const char* CCONV cmGetStartOutputDirectory(void* arg)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
return mf->GetCurrentBinaryDirectory();
2002-08-21 15:54:06 +00:00
}
const char* CCONV cmGetCurrentDirectory(void* arg)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
return mf->GetCurrentSourceDirectory();
2002-08-21 15:54:06 +00:00
}
const char* CCONV cmGetCurrentOutputDirectory(void* arg)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
return mf->GetCurrentBinaryDirectory();
2002-08-21 15:54:06 +00:00
}
const char* CCONV cmGetDefinition(void* arg, const char* def)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
2002-08-21 15:54:06 +00:00
return mf->GetDefinition(def);
}
int CCONV cmIsOn(void* arg, const char* name)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
2002-08-21 15:54:06 +00:00
return static_cast<int>(mf->IsOn(name));
}
/** Check if a command exists. */
int CCONV cmCommandExists(void* arg, const char* name)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
2015-04-11 10:52:14 +00:00
return static_cast<int>(mf->GetState()->GetCommand(name) ? 1 : 0);
2002-08-21 15:54:06 +00:00
}
void CCONV cmAddDefineFlag(void* arg, const char* definition)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
2002-08-21 15:54:06 +00:00
mf->AddDefineFlag(definition);
}
void CCONV cmAddLinkDirectoryForTarget(void* arg, const char* tgt,
const char* d)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
cmTarget* t = mf->FindLocalNonAliasTarget(tgt);
if (!t) {
cmSystemTools::Error(
"Attempt to add link directories to non-existent target: ", tgt,
" for directory ", d);
return;
}
t->AddLinkDirectory(d);
2002-08-21 15:54:06 +00:00
}
void CCONV cmAddExecutable(void* arg, const char* exename, int numSrcs,
const char** srcs, int win32)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
2002-08-21 15:54:06 +00:00
std::vector<std::string> srcs2;
int i;
for (i = 0; i < numSrcs; ++i) {
2002-08-21 15:54:06 +00:00
srcs2.push_back(srcs[i]);
}
cmTarget* tg = mf->AddExecutable(exename, srcs2);
if (win32) {
tg->SetProperty("WIN32_EXECUTABLE", "ON");
}
}
void CCONV cmAddUtilityCommand(void* arg, const char* utilityName,
const char* command, const char* arguments,
int all, int numDepends, const char** depends,
int, const char**)
2002-08-21 15:54:06 +00:00
{
// Get the makefile instance. Perform an extra variable expansion
// now because the API caller expects it.
cmMakefile* mf = static_cast<cmMakefile*>(arg);
// Construct the command line for the command.
cmCustomCommandLine commandLine;
std::string expand = command;
commandLine.push_back(mf->ExpandVariablesInString(expand));
if (arguments && arguments[0]) {
// TODO: Parse arguments!
expand = arguments;
commandLine.push_back(mf->ExpandVariablesInString(expand));
}
cmCustomCommandLines commandLines;
commandLines.push_back(commandLine);
// Accumulate the list of dependencies.
2002-08-21 15:54:06 +00:00
std::vector<std::string> depends2;
for (int i = 0; i < numDepends; ++i) {
expand = depends[i];
depends2.push_back(mf->ExpandVariablesInString(expand));
}
// Pass the call to the makefile instance.
2017-08-22 21:42:36 +00:00
mf->AddUtilityCommand(utilityName, (all ? false : true), nullptr, depends2,
commandLines);
2002-08-21 15:54:06 +00:00
}
void CCONV cmAddCustomCommand(void* arg, const char* source,
const char* command, int numArgs,
const char** args, int numDepends,
const char** depends, int numOutputs,
const char** outputs, const char* target)
2002-08-21 15:54:06 +00:00
{
// Get the makefile instance. Perform an extra variable expansion
// now because the API caller expects it.
cmMakefile* mf = static_cast<cmMakefile*>(arg);
// Construct the command line for the command.
cmCustomCommandLine commandLine;
std::string expand = command;
commandLine.push_back(mf->ExpandVariablesInString(expand));
for (int i = 0; i < numArgs; ++i) {
expand = args[i];
commandLine.push_back(mf->ExpandVariablesInString(expand));
}
cmCustomCommandLines commandLines;
commandLines.push_back(commandLine);
// Accumulate the list of dependencies.
2002-08-21 15:54:06 +00:00
std::vector<std::string> depends2;
for (int i = 0; i < numDepends; ++i) {
expand = depends[i];
depends2.push_back(mf->ExpandVariablesInString(expand));
}
// Accumulate the list of outputs.
2002-08-21 15:54:06 +00:00
std::vector<std::string> outputs2;
for (int i = 0; i < numOutputs; ++i) {
expand = outputs[i];
outputs2.push_back(mf->ExpandVariablesInString(expand));
}
// Pass the call to the makefile instance.
2017-08-22 21:42:36 +00:00
const char* no_comment = nullptr;
mf->AddCustomCommandOldStyle(target, outputs2, depends2, source,
commandLines, no_comment);
2002-08-21 15:54:06 +00:00
}
void CCONV cmAddCustomCommandToOutput(void* arg, const char* output,
const char* command, int numArgs,
const char** args,
const char* main_dependency,
int numDepends, const char** depends)
2003-06-03 14:30:23 +00:00
{
// Get the makefile instance. Perform an extra variable expansion
// now because the API caller expects it.
cmMakefile* mf = static_cast<cmMakefile*>(arg);
// Construct the command line for the command.
cmCustomCommandLine commandLine;
std::string expand = command;
commandLine.push_back(mf->ExpandVariablesInString(expand));
for (int i = 0; i < numArgs; ++i) {
expand = args[i];
commandLine.push_back(mf->ExpandVariablesInString(expand));
}
cmCustomCommandLines commandLines;
commandLines.push_back(commandLine);
// Accumulate the list of dependencies.
2003-06-03 14:30:23 +00:00
std::vector<std::string> depends2;
for (int i = 0; i < numDepends; ++i) {
expand = depends[i];
depends2.push_back(mf->ExpandVariablesInString(expand));
}
// Pass the call to the makefile instance.
2017-08-22 21:42:36 +00:00
const char* no_comment = nullptr;
const char* no_working_dir = nullptr;
mf->AddCustomCommandToOutput(output, depends2, main_dependency, commandLines,
no_comment, no_working_dir);
2003-06-03 14:30:23 +00:00
}
void CCONV cmAddCustomCommandToTarget(void* arg, const char* target,
const char* command, int numArgs,
const char** args, int commandType)
2003-06-03 14:30:23 +00:00
{
// Get the makefile instance.
cmMakefile* mf = static_cast<cmMakefile*>(arg);
// Construct the command line for the command. Perform an extra
// variable expansion now because the API caller expects it.
cmCustomCommandLine commandLine;
std::string expand = command;
commandLine.push_back(mf->ExpandVariablesInString(expand));
for (int i = 0; i < numArgs; ++i) {
expand = args[i];
commandLine.push_back(mf->ExpandVariablesInString(expand));
}
cmCustomCommandLines commandLines;
commandLines.push_back(commandLine);
// Select the command type.
cmTarget::CustomCommandType cctype = cmTarget::POST_BUILD;
switch (commandType) {
2003-06-03 14:30:23 +00:00
case CM_PRE_BUILD:
cctype = cmTarget::PRE_BUILD;
2003-06-03 14:30:23 +00:00
break;
case CM_PRE_LINK:
cctype = cmTarget::PRE_LINK;
2003-06-03 14:30:23 +00:00
break;
case CM_POST_BUILD:
cctype = cmTarget::POST_BUILD;
2003-06-03 14:30:23 +00:00
break;
}
// Pass the call to the makefile instance.
Add an option for explicit BYPRODUCTS of custom commands (#14963) A common idiom in CMake-based build systems is to have custom commands that generate files not listed explicitly as outputs so that these files do not have to be newer than the inputs. The file modification times of such "byproducts" are updated only when their content changes. Then other build rules can depend on the byproducts explicitly so that their dependents rebuild when the content of the original byproducts really does change. This "undeclared byproduct" approach is necessary for Makefile, VS, and Xcode build tools because if a byproduct were listed as an output of a rule then the rule would always rerun when the input is newer than the byproduct but the byproduct may never be updated. Ninja solves this problem by offering a 'restat' feature to check whether an output was really modified after running a rule and tracking the fact that it is up to date separately from its timestamp. However, Ninja also stats all dependencies up front and will only restat files that are listed as outputs of rules with the 'restat' option enabled. Therefore an undeclared byproduct that does not exist at the start of the build will be considered missing and the build will fail even if other dependencies would cause the byproduct to be available before its dependents build. CMake works around this limitation by adding 'phony' build rules for custom command dependencies in the build tree that do not have any explicit specification of what produces them. This is not optimal because it prevents Ninja from reporting an error when an input to a rule really is missing. A better approach is to allow projects to explicitly specify the byproducts of their custom commands so that no phony rules are needed for them. In order to work with the non-Ninja generators, the byproducts must be known separately from the outputs. Add a new "BYPRODUCTS" option to the add_custom_command and add_custom_target commands to specify byproducts explicitly. Teach the Ninja generator to specify byproducts as outputs of the custom commands. In the case of POST_BUILD, PRE_LINK, and PRE_BUILD events on targets that link, the byproducts must be specified as outputs of the link rule that runs the commands. Activate 'restat' for such rules so that Ninja knows it needs to check the byproducts, but not for link rules that have no byproducts.
2014-11-13 23:54:52 +00:00
std::vector<std::string> no_byproducts;
std::vector<std::string> no_depends;
2017-08-22 21:42:36 +00:00
const char* no_comment = nullptr;
const char* no_working_dir = nullptr;
Add an option for explicit BYPRODUCTS of custom commands (#14963) A common idiom in CMake-based build systems is to have custom commands that generate files not listed explicitly as outputs so that these files do not have to be newer than the inputs. The file modification times of such "byproducts" are updated only when their content changes. Then other build rules can depend on the byproducts explicitly so that their dependents rebuild when the content of the original byproducts really does change. This "undeclared byproduct" approach is necessary for Makefile, VS, and Xcode build tools because if a byproduct were listed as an output of a rule then the rule would always rerun when the input is newer than the byproduct but the byproduct may never be updated. Ninja solves this problem by offering a 'restat' feature to check whether an output was really modified after running a rule and tracking the fact that it is up to date separately from its timestamp. However, Ninja also stats all dependencies up front and will only restat files that are listed as outputs of rules with the 'restat' option enabled. Therefore an undeclared byproduct that does not exist at the start of the build will be considered missing and the build will fail even if other dependencies would cause the byproduct to be available before its dependents build. CMake works around this limitation by adding 'phony' build rules for custom command dependencies in the build tree that do not have any explicit specification of what produces them. This is not optimal because it prevents Ninja from reporting an error when an input to a rule really is missing. A better approach is to allow projects to explicitly specify the byproducts of their custom commands so that no phony rules are needed for them. In order to work with the non-Ninja generators, the byproducts must be known separately from the outputs. Add a new "BYPRODUCTS" option to the add_custom_command and add_custom_target commands to specify byproducts explicitly. Teach the Ninja generator to specify byproducts as outputs of the custom commands. In the case of POST_BUILD, PRE_LINK, and PRE_BUILD events on targets that link, the byproducts must be specified as outputs of the link rule that runs the commands. Activate 'restat' for such rules so that Ninja knows it needs to check the byproducts, but not for link rules that have no byproducts.
2014-11-13 23:54:52 +00:00
mf->AddCustomCommandToTarget(target, no_byproducts, no_depends, commandLines,
2006-02-08 15:58:36 +00:00
cctype, no_comment, no_working_dir);
2003-06-03 14:30:23 +00:00
}
2002-08-21 15:54:06 +00:00
static void addLinkLibrary(cmMakefile* mf, std::string const& target,
std::string const& lib, cmTargetLinkLibraryType llt)
{
cmTarget* t = mf->FindLocalNonAliasTarget(target);
if (!t) {
std::ostringstream e;
e << "Attempt to add link library \"" << lib << "\" to target \"" << target
<< "\" which is not built in this directory.";
mf->IssueMessage(cmake::FATAL_ERROR, e.str());
return;
}
cmTarget* tgt = mf->GetGlobalGenerator()->FindTarget(lib);
if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) &&
(tgt->GetType() != cmStateEnums::SHARED_LIBRARY) &&
(tgt->GetType() != cmStateEnums::INTERFACE_LIBRARY) &&
!tgt->IsExecutableWithExports()) {
std::ostringstream e;
e << "Target \"" << lib << "\" of type "
<< cmState::GetTargetTypeName(tgt->GetType())
<< " may not be linked into another target. "
<< "One may link only to STATIC or SHARED libraries, or "
<< "to executables with the ENABLE_EXPORTS property set.";
mf->IssueMessage(cmake::FATAL_ERROR, e.str());
}
t->AddLinkLibrary(*mf, lib, llt);
}
void CCONV cmAddLinkLibraryForTarget(void* arg, const char* tgt,
const char* value, int libtype)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
2006-03-10 18:06:26 +00:00
switch (libtype) {
2002-08-21 15:54:06 +00:00
case CM_LIBRARY_GENERAL:
addLinkLibrary(mf, tgt, value, GENERAL_LibraryType);
2002-08-21 15:54:06 +00:00
break;
case CM_LIBRARY_DEBUG:
addLinkLibrary(mf, tgt, value, DEBUG_LibraryType);
2002-08-21 15:54:06 +00:00
break;
case CM_LIBRARY_OPTIMIZED:
addLinkLibrary(mf, tgt, value, OPTIMIZED_LibraryType);
2002-08-21 15:54:06 +00:00
break;
}
2002-08-21 15:54:06 +00:00
}
void CCONV cmAddLibrary(void* arg, const char* libname, int shared,
int numSrcs, const char** srcs)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
2002-08-21 15:54:06 +00:00
std::vector<std::string> srcs2;
int i;
for (i = 0; i < numSrcs; ++i) {
2002-08-21 15:54:06 +00:00
srcs2.push_back(srcs[i]);
}
mf->AddLibrary(libname, (shared ? cmStateEnums::SHARED_LIBRARY
: cmStateEnums::STATIC_LIBRARY),
srcs2);
2002-08-21 15:54:06 +00:00
}
char CCONV* cmExpandVariablesInString(void* arg, const char* source,
int escapeQuotes, int atOnly)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
2002-08-21 17:16:07 +00:00
std::string barf = source;
std::string result = mf->ExpandVariablesInString(
barf, (escapeQuotes ? true : false), (atOnly ? true : false));
char* res = static_cast<char*>(malloc(result.size() + 1));
2016-11-05 22:44:29 +00:00
if (!result.empty()) {
strcpy(res, result.c_str());
}
2002-08-21 15:54:06 +00:00
res[result.size()] = '\0';
return res;
}
int CCONV cmExecuteCommand(void* arg, const char* name, int numArgs,
const char** args)
2002-08-21 15:54:06 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
cmListFileFunction lff;
2006-03-15 16:02:08 +00:00
lff.Name = name;
for (int i = 0; i < numArgs; ++i) {
// Assume all arguments are quoted.
lff.Arguments.push_back(
cmListFileArgument(args[i], cmListFileArgument::Quoted, 0));
}
cmExecutionStatus status;
return mf->ExecuteCommand(lff, status);
2002-08-21 15:54:06 +00:00
}
void CCONV cmExpandSourceListArguments(void* arg, int numArgs,
const char** args, int* resArgc,
char*** resArgv,
unsigned int startArgumentIndex)
2002-08-21 15:54:06 +00:00
{
(void)arg;
(void)startArgumentIndex;
2002-08-21 15:54:06 +00:00
std::vector<std::string> result;
int i;
for (i = 0; i < numArgs; ++i) {
result.push_back(args[i]);
}
2002-08-23 19:13:49 +00:00
int resargc = static_cast<int>(result.size());
2017-08-22 21:42:36 +00:00
char** resargv = nullptr;
if (resargc) {
resargv = (char**)malloc(resargc * sizeof(char*));
}
for (i = 0; i < resargc; ++i) {
2002-08-21 15:54:06 +00:00
resargv[i] = strdup(result[i].c_str());
}
2002-08-21 15:54:06 +00:00
*resArgc = resargc;
*resArgv = resargv;
}
void CCONV cmFreeArguments(int argc, char** argv)
2002-08-21 15:54:06 +00:00
{
int i;
for (i = 0; i < argc; ++i) {
2002-08-21 15:54:06 +00:00
free(argv[i]);
}
if (argv) {
2002-08-21 15:54:06 +00:00
free(argv);
}
2002-08-21 15:54:06 +00:00
}
int CCONV cmGetTotalArgumentSize(int argc, char** argv)
2002-08-21 15:54:06 +00:00
{
int i;
int result = 0;
for (i = 0; i < argc; ++i) {
if (argv[i]) {
2002-08-23 19:13:49 +00:00
result = result + static_cast<int>(strlen(argv[i]));
2002-08-21 15:54:06 +00:00
}
}
2002-08-21 15:54:06 +00:00
return result;
}
// Source file proxy object to support the old cmSourceFile/cmMakefile
// API for source files.
struct cmCPluginAPISourceFile
{
cmCPluginAPISourceFile()
2017-08-22 21:42:36 +00:00
: RealSourceFile(nullptr)
{
}
cmSourceFile* RealSourceFile;
std::string SourceName;
std::string SourceExtension;
std::string FullPath;
std::vector<std::string> Depends;
cmPropertyMap Properties;
};
// Keep a map from real cmSourceFile instances stored in a makefile to
// the CPluginAPI proxy source file.
class cmCPluginAPISourceFileMap
: public std::map<cmSourceFile*, cmCPluginAPISourceFile*>
{
public:
typedef std::map<cmSourceFile*, cmCPluginAPISourceFile*> derived;
typedef derived::iterator iterator;
typedef derived::value_type value_type;
~cmCPluginAPISourceFileMap()
{
for (iterator i = this->begin(); i != this->end(); ++i) {
delete i->second;
}
}
};
cmCPluginAPISourceFileMap cmCPluginAPISourceFiles;
void* CCONV cmCreateSourceFile(void)
2002-08-21 15:54:06 +00:00
{
return (void*)new cmCPluginAPISourceFile;
2002-08-21 15:54:06 +00:00
}
void* CCONV cmCreateNewSourceFile(void*)
2002-08-21 15:54:06 +00:00
{
cmCPluginAPISourceFile* sf = new cmCPluginAPISourceFile;
return (void*)sf;
2002-08-21 15:54:06 +00:00
}
void CCONV cmDestroySourceFile(void* arg)
2002-08-21 15:54:06 +00:00
{
cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
// Only delete if it was created by cmCreateSourceFile or
// cmCreateNewSourceFile and is therefore not in the map.
if (!sf->RealSourceFile) {
delete sf;
}
2002-08-21 15:54:06 +00:00
}
void CCONV* cmGetSource(void* arg, const char* name)
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
if (cmSourceFile* rsf = mf->GetSource(name)) {
// Lookup the proxy source file object for this source.
cmCPluginAPISourceFileMap::iterator i = cmCPluginAPISourceFiles.find(rsf);
if (i == cmCPluginAPISourceFiles.end()) {
// Create a proxy source file object for this source.
cmCPluginAPISourceFile* sf = new cmCPluginAPISourceFile;
sf->RealSourceFile = rsf;
sf->FullPath = rsf->GetFullPath();
sf->SourceName =
cmSystemTools::GetFilenameWithoutLastExtension(sf->FullPath);
sf->SourceExtension =
cmSystemTools::GetFilenameLastExtension(sf->FullPath);
// Store the proxy in the map so it can be re-used and deleted later.
cmCPluginAPISourceFileMap::value_type entry(rsf, sf);
i = cmCPluginAPISourceFiles.insert(entry).first;
}
return (void*)i->second;
}
2017-08-22 21:42:36 +00:00
return nullptr;
}
void* CCONV cmAddSource(void* arg, void* arg2)
2002-12-11 19:16:55 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
cmCPluginAPISourceFile* osf = static_cast<cmCPluginAPISourceFile*>(arg2);
if (osf->FullPath.empty()) {
2017-08-22 21:42:36 +00:00
return nullptr;
}
// Create the real cmSourceFile instance and copy over saved information.
cmSourceFile* rsf = mf->GetOrCreateSource(osf->FullPath);
rsf->GetProperties() = osf->Properties;
for (std::vector<std::string>::iterator i = osf->Depends.begin();
i != osf->Depends.end(); ++i) {
2016-11-05 22:44:29 +00:00
rsf->AddDepend(*i);
}
// Create the proxy for the real source file.
cmCPluginAPISourceFile* sf = new cmCPluginAPISourceFile;
sf->RealSourceFile = rsf;
sf->FullPath = osf->FullPath;
sf->SourceName = osf->SourceName;
sf->SourceExtension = osf->SourceExtension;
// Store the proxy in the map so it can be re-used and deleted later.
cmCPluginAPISourceFiles[rsf] = sf;
return (void*)sf;
2002-12-11 19:16:55 +00:00
}
const char* CCONV cmSourceFileGetSourceName(void* arg)
2002-08-21 15:54:06 +00:00
{
cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
return sf->SourceName.c_str();
2002-08-21 15:54:06 +00:00
}
const char* CCONV cmSourceFileGetFullPath(void* arg)
2002-11-14 16:03:08 +00:00
{
cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
return sf->FullPath.c_str();
2002-11-14 16:03:08 +00:00
}
const char* CCONV cmSourceFileGetProperty(void* arg, const char* prop)
2002-08-21 15:54:06 +00:00
{
cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
if (cmSourceFile* rsf = sf->RealSourceFile) {
return rsf->GetProperty(prop);
}
2016-09-16 20:45:24 +00:00
if (!strcmp(prop, "LOCATION")) {
return sf->FullPath.c_str();
}
return sf->Properties.GetPropertyValue(prop);
2002-08-21 15:54:06 +00:00
}
int CCONV cmSourceFileGetPropertyAsBool(void* arg, const char* prop)
2002-08-21 15:54:06 +00:00
{
cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
if (cmSourceFile* rsf = sf->RealSourceFile) {
return rsf->GetPropertyAsBool(prop) ? 1 : 0;
}
2016-09-16 20:45:24 +00:00
return cmSystemTools::IsOn(cmSourceFileGetProperty(arg, prop)) ? 1 : 0;
2002-08-21 15:54:06 +00:00
}
void CCONV cmSourceFileSetProperty(void* arg, const char* prop,
const char* value)
2002-08-21 15:54:06 +00:00
{
cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
if (cmSourceFile* rsf = sf->RealSourceFile) {
rsf->SetProperty(prop, value);
} else if (prop) {
if (!value) {
value = "NOTFOUND";
}
sf->Properties.SetProperty(prop, value);
}
2002-08-21 15:54:06 +00:00
}
void CCONV cmSourceFileAddDepend(void* arg, const char* depend)
2002-08-21 15:54:06 +00:00
{
cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
if (cmSourceFile* rsf = sf->RealSourceFile) {
rsf->AddDepend(depend);
} else {
sf->Depends.push_back(depend);
}
2002-08-21 15:54:06 +00:00
}
void CCONV cmSourceFileSetName(void* arg, const char* name, const char* dir,
int numSourceExtensions,
const char** sourceExtensions,
int numHeaderExtensions,
const char** headerExtensions)
{
cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
if (sf->RealSourceFile) {
// SetName is allowed only on temporary source files created by
// the command for building and passing to AddSource.
return;
}
std::vector<std::string> sourceExts;
std::vector<std::string> headerExts;
2002-08-21 15:54:06 +00:00
int i;
for (i = 0; i < numSourceExtensions; ++i) {
sourceExts.push_back(sourceExtensions[i]);
}
for (i = 0; i < numHeaderExtensions; ++i) {
headerExts.push_back(headerExtensions[i]);
}
// Save the original name given.
sf->SourceName = name;
// Convert the name to a full path in case the given name is a
// relative path.
std::string pathname = cmSystemTools::CollapseFullPath(name, dir);
// First try and see whether the listed file can be found
// as is without extensions added on.
std::string hname = pathname;
if (cmSystemTools::FileExists(hname.c_str())) {
sf->SourceName = cmSystemTools::GetFilenamePath(name);
2016-11-05 22:44:29 +00:00
if (!sf->SourceName.empty()) {
sf->SourceName += "/";
}
sf->SourceName += cmSystemTools::GetFilenameWithoutLastExtension(name);
std::string::size_type pos = hname.rfind('.');
if (pos != std::string::npos) {
sf->SourceExtension = hname.substr(pos + 1, hname.size() - pos);
if (cmSystemTools::FileIsFullPath(name)) {
std::string::size_type pos2 = hname.rfind('/');
if (pos2 != std::string::npos) {
sf->SourceName = hname.substr(pos2 + 1, pos - pos2 - 1);
}
}
}
sf->FullPath = hname;
return;
}
// Next, try the various source extensions
for (std::vector<std::string>::const_iterator ext = sourceExts.begin();
ext != sourceExts.end(); ++ext) {
hname = pathname;
hname += ".";
hname += *ext;
if (cmSystemTools::FileExists(hname.c_str())) {
sf->SourceExtension = *ext;
sf->FullPath = hname;
return;
}
}
// Finally, try the various header extensions
for (std::vector<std::string>::const_iterator ext = headerExts.begin();
ext != headerExts.end(); ++ext) {
hname = pathname;
hname += ".";
hname += *ext;
if (cmSystemTools::FileExists(hname.c_str())) {
sf->SourceExtension = *ext;
sf->FullPath = hname;
return;
}
}
std::ostringstream e;
e << "Cannot find source file \"" << pathname << "\"";
e << "\n\nTried extensions";
for (std::vector<std::string>::const_iterator ext = sourceExts.begin();
ext != sourceExts.end(); ++ext) {
e << " ." << *ext;
}
for (std::vector<std::string>::const_iterator ext = headerExts.begin();
ext != headerExts.end(); ++ext) {
e << " ." << *ext;
}
cmSystemTools::Error(e.str().c_str());
2002-08-21 15:54:06 +00:00
}
void CCONV cmSourceFileSetName2(void* arg, const char* name, const char* dir,
const char* ext, int headerFileOnly)
2002-08-21 15:54:06 +00:00
{
cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
if (sf->RealSourceFile) {
// SetName is allowed only on temporary source files created by
// the command for building and passing to AddSource.
return;
}
2002-08-21 15:54:06 +00:00
// Implement the old SetName method code here.
if (headerFileOnly) {
sf->Properties.SetProperty("HEADER_FILE_ONLY", "1");
}
sf->SourceName = name;
std::string fname = sf->SourceName;
if (ext && strlen(ext)) {
fname += ".";
fname += ext;
}
2016-11-05 22:44:29 +00:00
sf->FullPath = cmSystemTools::CollapseFullPath(fname, dir);
cmSystemTools::ConvertToUnixSlashes(sf->FullPath);
sf->SourceExtension = ext;
}
2002-08-21 15:54:06 +00:00
char* CCONV cmGetFilenameWithoutExtension(const char* name)
2002-08-21 15:54:06 +00:00
{
std::string sres = cmSystemTools::GetFilenameWithoutExtension(name);
char* result = (char*)malloc(sres.size() + 1);
strcpy(result, sres.c_str());
2002-08-21 15:54:06 +00:00
return result;
}
char* CCONV cmGetFilenamePath(const char* name)
2002-11-14 16:16:58 +00:00
{
std::string sres = cmSystemTools::GetFilenamePath(name);
char* result = (char*)malloc(sres.size() + 1);
strcpy(result, sres.c_str());
2002-11-14 16:16:58 +00:00
return result;
}
char* CCONV cmCapitalized(const char* name)
2002-08-21 15:54:06 +00:00
{
std::string sres = cmSystemTools::Capitalized(name);
char* result = (char*)malloc(sres.size() + 1);
strcpy(result, sres.c_str());
2002-08-21 15:54:06 +00:00
return result;
}
void CCONV cmCopyFileIfDifferent(const char* name1, const char* name2)
2002-08-21 15:54:06 +00:00
{
cmSystemTools::CopyFileIfDifferent(name1, name2);
2002-08-21 15:54:06 +00:00
}
void CCONV cmRemoveFile(const char* name)
2002-08-21 15:54:06 +00:00
{
cmSystemTools::RemoveFile(name);
}
void CCONV cmDisplayStatus(void* arg, const char* message)
2003-07-22 17:14:55 +00:00
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
mf->DisplayStatus(message, -1);
2003-07-22 17:14:55 +00:00
}
void CCONV cmFree(void* data)
2002-12-11 19:16:55 +00:00
{
free(data);
}
void CCONV DefineSourceFileProperty(void* arg, const char* name,
const char* briefDocs,
const char* longDocs, int chained)
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
mf->GetState()->DefineProperty(name, cmProperty::SOURCE_FILE, briefDocs,
longDocs, chained != 0);
}
2002-08-29 13:45:34 +00:00
} // close the extern "C" scope
cmCAPI cmStaticCAPI = {
2002-08-26 14:52:04 +00:00
cmGetClientData,
2002-10-08 19:55:04 +00:00
cmGetTotalArgumentSize,
cmFreeArguments,
cmSetClientData,
cmSetError,
cmAddCacheDefinition,
cmAddCustomCommand,
cmAddDefineFlag,
cmAddDefinition,
cmAddExecutable,
cmAddLibrary,
cmAddLinkDirectoryForTarget,
cmAddLinkLibraryForTarget,
cmAddUtilityCommand,
cmCommandExists,
cmExecuteCommand,
cmExpandSourceListArguments,
cmExpandVariablesInString,
cmGetCacheMajorVersion,
cmGetCacheMinorVersion,
cmGetCurrentDirectory,
cmGetCurrentOutputDirectory,
cmGetDefinition,
cmGetHomeDirectory,
cmGetHomeOutputDirectory,
cmGetMajorVersion,
cmGetMinorVersion,
cmGetProjectName,
cmGetStartDirectory,
cmGetStartOutputDirectory,
cmIsOn,
2006-03-10 18:06:26 +00:00
2002-10-08 19:55:04 +00:00
cmAddSource,
cmCreateSourceFile,
2002-12-11 19:16:55 +00:00
cmDestroySourceFile,
2002-10-08 19:55:04 +00:00
cmGetSource,
cmSourceFileAddDepend,
cmSourceFileGetProperty,
cmSourceFileGetPropertyAsBool,
cmSourceFileGetSourceName,
2002-11-14 16:03:08 +00:00
cmSourceFileGetFullPath,
2002-10-08 19:55:04 +00:00
cmSourceFileSetName,
cmSourceFileSetName2,
cmSourceFileSetProperty,
2006-03-10 18:06:26 +00:00
2002-10-08 19:55:04 +00:00
cmCapitalized,
cmCopyFileIfDifferent,
cmGetFilenameWithoutExtension,
2002-11-14 16:16:58 +00:00
cmGetFilenamePath,
2002-10-08 19:55:04 +00:00
cmRemoveFile,
2002-12-11 19:16:55 +00:00
cmFree,
2003-06-03 14:30:23 +00:00
cmAddCustomCommandToOutput,
cmAddCustomCommandToTarget,
2003-07-23 18:31:30 +00:00
cmDisplayStatus,
cmCreateNewSourceFile,
DefineSourceFileProperty,
2002-08-26 14:52:04 +00:00
};