Parcourir la source

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 il y a 3 ans
Parent
commit
611d801790

+ 12 - 1
Help/command/try_compile.rst

@@ -58,7 +58,8 @@ Try Compiling Source Files
   try_compile(<resultVar>
   try_compile(<resultVar>
               <SOURCES <srcfile...>]             |
               <SOURCES <srcfile...>]             |
                SOURCE_FROM_ARG <name> <content>] |
                SOURCE_FROM_ARG <name> <content>] |
-               SOURCE_FROM_VAR <name> <var>]     >...
+               SOURCE_FROM_VAR <name> <var>]     |
+               SOURCE_FROM_FILE <name> <path>    >...
               [CMAKE_FLAGS <flags>...]
               [CMAKE_FLAGS <flags>...]
               [COMPILE_DEFINITIONS <defs>...]
               [COMPILE_DEFINITIONS <defs>...]
               [LINK_OPTIONS <options>...]
               [LINK_OPTIONS <options>...]
@@ -178,6 +179,16 @@ The options are:
 
 
   ``SOURCE_FROM_ARG`` may be specified multiple times.
   ``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>``
 ``SOURCE_FROM_VAR <name> <content>``
   .. versionadded:: 3.25
   .. versionadded:: 3.25
 
 

+ 2 - 1
Help/command/try_run.rst

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

+ 32 - 0
Source/cmCoreTryCompile.cxx

@@ -174,6 +174,7 @@ auto const TryCompileBaseNewSourcesArgParser =
   cmArgumentParser<Arguments>{ TryCompileBaseSourcesArgParser }
   cmArgumentParser<Arguments>{ TryCompileBaseSourcesArgParser }
     .Bind("SOURCE_FROM_ARG"_s, &Arguments::SourceFromArg)
     .Bind("SOURCE_FROM_ARG"_s, &Arguments::SourceFromArg)
     .Bind("SOURCE_FROM_VAR"_s, &Arguments::SourceFromVar)
     .Bind("SOURCE_FROM_VAR"_s, &Arguments::SourceFromVar)
+    .Bind("SOURCE_FROM_FILE"_s, &Arguments::SourceFromFile)
   /* keep semicolon on own line */;
   /* keep semicolon on own line */;
 
 
 auto const TryCompileBaseProjectArgParser =
 auto const TryCompileBaseProjectArgParser =
@@ -416,6 +417,12 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
         "SOURCE_FROM_VAR requires exactly two arguments");
         "SOURCE_FROM_VAR requires exactly two arguments");
       return false;
       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 {
   } else {
     // only valid for srcfile signatures
     // only valid for srcfile signatures
     if (!arguments.LangProps.empty()) {
     if (!arguments.LangProps.empty()) {
@@ -497,6 +504,31 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
         sources.emplace_back(std::move(out));
         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
     // TODO: ensure sources is not empty
 
 
     // Detect languages to enable.
     // Detect languages to enable.

+ 2 - 0
Source/cmCoreTryCompile.h

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

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

@@ -23,6 +23,7 @@ unset(RunCMake_TEST_OPTIONS)
 run_cmake(SourceFromOneArg)
 run_cmake(SourceFromOneArg)
 run_cmake(SourceFromThreeArgs)
 run_cmake(SourceFromThreeArgs)
 run_cmake(SourceFromBadName)
 run_cmake(SourceFromBadName)
+run_cmake(SourceFromBadFile)
 
 
 run_cmake(ProjectCopyFile)
 run_cmake(ProjectCopyFile)
 run_cmake(NonSourceCopyFile)
 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?")
   message(SEND_ERROR "Trying to compile an empty source succeeded?")
 endif()
 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
 # try to run a source specified directly
 set(TRY_RUN_MAIN_CODE
 set(TRY_RUN_MAIN_CODE
   "extern int answer(); \n"
   "extern int answer(); \n"