Răsfoiți Sursa

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.
Matthew Woehlke 3 ani în urmă
părinte
comite
611d801790

+ 12 - 1
Help/command/try_compile.rst

@@ -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
 

+ 2 - 1
Help/command/try_run.rst

@@ -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>...]

+ 32 - 0
Source/cmCoreTryCompile.cxx

@@ -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.

+ 2 - 0
Source/cmCoreTryCompile.h

@@ -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]

+ 1 - 0
Tests/RunCMake/try_compile/RunCMakeTest.cmake

@@ -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)

+ 1 - 0
Tests/RunCMake/try_compile/SourceFromBadFile-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/try_compile/SourceFromBadFile-stderr.txt

@@ -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\)

+ 1 - 0
Tests/RunCMake/try_compile/SourceFromBadFile.cmake

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

+ 6 - 0
Tests/TryCompile/CMakeLists.txt

@@ -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"