try_compile: Add SOURCE_FROM_FILE

Add ability to copy try_compile (and try_run) source files from
arbitrary locations into the operation directory. This is included for
the sake of completion and consolidation, although use cases which
actually require this may be rare.
This commit is contained in:
Matthew Woehlke 2022-09-22 13:43:14 -04:00
parent a04eaf6742
commit 611d801790
9 changed files with 61 additions and 2 deletions

View File

@ -58,7 +58,8 @@ Try Compiling Source Files
try_compile(<resultVar>
<SOURCES <srcfile...>] |
SOURCE_FROM_ARG <name> <content>] |
SOURCE_FROM_VAR <name> <var>] >...
SOURCE_FROM_VAR <name> <var>] |
SOURCE_FROM_FILE <name> <path> >...
[CMAKE_FLAGS <flags>...]
[COMPILE_DEFINITIONS <defs>...]
[LINK_OPTIONS <options>...]
@ -178,6 +179,16 @@ The options are:
``SOURCE_FROM_ARG`` may be specified multiple times.
``SOURCE_FROM_FILE <name> <path>``
.. versionadded:: 3.25
Copy ``<path>`` to a file named ``<name>`` in the operation directory. This
can be used to consolidate files into the operation directory, which may be
useful if a source which already exists (i.e. as a stand-alone file in a
project's source repository) needs to refer to other file(s) created by
``SOURCE_FROM_*``. (Otherwise, ``SOURCES`` is usually more convenient.) The
specified ``<name>`` is not allowed to contain path components.
``SOURCE_FROM_VAR <name> <content>``
.. versionadded:: 3.25

View File

@ -15,7 +15,8 @@ Try Compiling and Running Source Files
try_run(<runResultVar> <compileResultVar>
<SOURCES <srcfile...>] |
SOURCE_FROM_ARG <name> <content>] |
SOURCE_FROM_VAR <name> <var>] >...
SOURCE_FROM_VAR <name> <var>] |
SOURCE_FROM_FILE <name> <path> >...
[CMAKE_FLAGS <flags>...]
[COMPILE_DEFINITIONS <defs>...]
[LINK_OPTIONS <options>...]

View File

@ -174,6 +174,7 @@ auto const TryCompileBaseNewSourcesArgParser =
cmArgumentParser<Arguments>{ TryCompileBaseSourcesArgParser }
.Bind("SOURCE_FROM_ARG"_s, &Arguments::SourceFromArg)
.Bind("SOURCE_FROM_VAR"_s, &Arguments::SourceFromVar)
.Bind("SOURCE_FROM_FILE"_s, &Arguments::SourceFromFile)
/* keep semicolon on own line */;
auto const TryCompileBaseProjectArgParser =
@ -416,6 +417,12 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
"SOURCE_FROM_VAR requires exactly two arguments");
return false;
}
if (arguments.SourceFromFile && arguments.SourceFromFile->size() % 2) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"SOURCE_FROM_FILE requires exactly two arguments");
return false;
}
} else {
// only valid for srcfile signatures
if (!arguments.LangProps.empty()) {
@ -497,6 +504,31 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
sources.emplace_back(std::move(out));
}
}
if (arguments.SourceFromFile) {
auto const k = arguments.SourceFromFile->size();
for (auto i = decltype(k){ 0 }; i < k; i += 2) {
const auto& dst = (*arguments.SourceFromFile)[i + 0];
const auto& src = (*arguments.SourceFromFile)[i + 1];
if (!cmSystemTools::GetFilenamePath(dst).empty()) {
const auto& msg =
cmStrCat("SOURCE_FROM_FILE given invalid filename \"", dst, "\"");
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
return false;
}
auto dstPath = cmStrCat(this->BinaryDirectory, "/", dst);
auto const result = cmSystemTools::CopyFileAlways(src, dstPath);
if (!result.IsSuccess()) {
const auto& msg = cmStrCat("SOURCE_FROM_FILE failed to copy \"", src,
"\": ", result.GetString());
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
return false;
}
sources.emplace_back(std::move(dstPath));
}
}
// TODO: ensure sources is not empty
// Detect languages to enable.

View File

@ -44,6 +44,8 @@ public:
SourceFromArg;
cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>>
SourceFromVar;
cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>>
SourceFromFile;
ArgumentParser::MaybeEmpty<std::vector<std::string>> CMakeFlags{
1, "CMAKE_FLAGS"
}; // fake argv[0]

View File

@ -23,6 +23,7 @@ unset(RunCMake_TEST_OPTIONS)
run_cmake(SourceFromOneArg)
run_cmake(SourceFromThreeArgs)
run_cmake(SourceFromBadName)
run_cmake(SourceFromBadFile)
run_cmake(ProjectCopyFile)
run_cmake(NonSourceCopyFile)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at SourceFromBadFile.cmake:[0-9]+ \(try_compile\):
SOURCE_FROM_FILE failed to copy "bad#source.c": No such file or directory
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1 @@
try_compile(RESULT SOURCE_FROM_FILE bad.c "bad#source.c")

View File

@ -89,6 +89,12 @@ if(SHOULD_FAIL_DUE_TO_EMPTY_SOURCE)
message(SEND_ERROR "Trying to compile an empty source succeeded?")
endif()
# try to compile a copied source
try_compile(SHOULD_PASS
SOURCE_FROM_FILE pass.c ${TryCompile_SOURCE_DIR}/pass.c
OUTPUT_VARIABLE TRY_OUT)
EXPECT_COMPILED("SOURCE_FROM_FILE" SHOULD_PASS "${TRY_OUT}")
# try to run a source specified directly
set(TRY_RUN_MAIN_CODE
"extern int answer(); \n"