ソースを参照

fileapi: Add cross-compiling emulator to codemodel-v2

Fixes: #25408
Ralf Habacker 1 年間 前
コミット
80a64c9ce5

+ 27 - 1
Help/manual/cmake-file-api.7.rst

@@ -431,7 +431,7 @@ Version 1 does not exist to avoid confusion with that from
 
   {
     "kind": "codemodel",
-    "version": { "major": 2, "minor": 6 },
+    "version": { "major": 2, "minor": 7 },
     "paths": {
       "source": "/path/to/top-level-source-dir",
       "build": "/path/to/top-level-build-dir"
@@ -998,6 +998,32 @@ with members:
       destination is available.  The value is an unsigned integer 0-based
       index into the ``backtraceGraph`` member's ``nodes`` array.
 
+  ``launchers``
+    Optional member that is present on executable targets that have
+    at least one launcher specified by the project.  The value is a
+    JSON array of entries corresponding to the specified launchers.
+    Each entry is a JSON object with members:
+
+    ``command``
+      A string specifying the path to the launcher on disk, represented
+      with forward slashes. If the file is inside the top-level source
+      directory then the path is specified relative to that directory.
+
+    ``arguments``
+      Optional member that is present when the launcher command has
+      arguments preceding the executable to be launched.  The value
+      is a JSON array of strings representing the arguments.
+
+    ``type``
+      A string specifying the type of launcher.  The value is one of
+      the following:
+
+      ``emulator``
+        An emulator for the target platform when cross-compiling.
+        See the :prop_tgt:`CROSSCOMPILING_EMULATOR` target property.
+
+    This field was added in codemodel version 2.7.
+
 ``link``
   Optional member that is present for executables and shared library
   targets that link into a runtime binary.  The value is a JSON object

+ 7 - 0
Help/release/dev/fileapi-exe-launcher.rst

@@ -0,0 +1,7 @@
+fileapi-exe-launcher
+--------------------
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 ``version`` field has
+  been updated to 2.7.
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 "target" object gained
+  a new "launchers" field.

+ 1 - 1
Source/cmFileAPI.cxx

@@ -727,7 +727,7 @@ std::string cmFileAPI::NoSupportedVersion(
 // The "codemodel" object kind.
 
 // Update Help/manual/cmake-file-api.7.rst when updating this constant.
-static unsigned int const CodeModelV2Minor = 6;
+static unsigned int const CodeModelV2Minor = 7;
 
 void cmFileAPI::BuildClientRequestCodeModel(
   ClientRequest& r, std::vector<RequestVersion> const& versions)

+ 46 - 0
Source/cmFileAPICodemodel.cxx

@@ -41,10 +41,12 @@
 #include "cmInstallSubdirectoryGenerator.h"
 #include "cmInstallTargetGenerator.h"
 #include "cmLinkLineComputer.h" // IWYU pragma: keep
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmSourceGroup.h"
 #include "cmState.h"
@@ -503,6 +505,8 @@ class Target
   Json::Value DumpDependencies();
   Json::Value DumpDependency(cmTargetDepend const& td);
   Json::Value DumpFolder();
+  Json::Value DumpLauncher(const char* name, const char* type);
+  Json::Value DumpLaunchers();
 
 public:
   Target(cmGeneratorTarget* gt, std::string const& config);
@@ -1223,6 +1227,13 @@ Json::Value Target::Dump()
     target["archive"] = this->DumpArchive();
   }
 
+  if (type == cmStateEnums::EXECUTABLE) {
+    Json::Value launchers = this->DumpLaunchers();
+    if (!launchers.empty()) {
+      target["launchers"] = std::move(launchers);
+    }
+  }
+
   Json::Value dependencies = this->DumpDependencies();
   if (!dependencies.empty()) {
     target["dependencies"] = dependencies;
@@ -2075,6 +2086,41 @@ Json::Value Target::DumpFolder()
   }
   return folder;
 }
+
+Json::Value Target::DumpLauncher(const char* name, const char* type)
+{
+  cmValue property = this->GT->GetProperty(name);
+  Json::Value launcher;
+  if (property) {
+    cmList commandWithArgs{ *property };
+    std::string command(commandWithArgs[0]);
+    cmSystemTools::ConvertToUnixSlashes(command);
+    launcher = Json::objectValue;
+    launcher["command"] = RelativeIfUnder(this->TopSource, command);
+    launcher["type"] = type;
+    Json::Value args;
+    for (std::string const& arg : cmMakeRange(commandWithArgs).advance(1)) {
+      args.append(arg);
+    }
+    launcher["arguments"] = args;
+  }
+  return launcher;
+}
+
+Json::Value Target::DumpLaunchers()
+{
+  Json::Value launchers;
+  bool allow =
+    this->GT->Makefile->GetDefinition("CMAKE_CROSSCOMPILING").IsOn();
+  Json::Value launcher;
+  if (allow) {
+    launcher = DumpLauncher("CROSSCOMPILING_EMULATOR", "emulator");
+    if (!launcher.empty()) {
+      launchers.append(launcher);
+    }
+  }
+  return launchers;
+}
 }
 
 Json::Value cmFileAPICodemodelDump(cmFileAPI& fileAPI, unsigned long version)

+ 1 - 1
Tests/RunCMake/CommandLine/E_capabilities-stdout.txt

@@ -1 +1 @@
-^{"debugger":(true|false),"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":6}]},{"kind":"configureLog","version":\[{"major":1,"minor":0}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"tls":(true|false),"version":{.*}}$
+^{"debugger":(true|false),"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":7}]},{"kind":"configureLog","version":\[{"major":1,"minor":0}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"tls":(true|false),"version":{.*}}$

+ 25 - 1
Tests/RunCMake/FileAPI/codemodel-v2-check.py

@@ -12,7 +12,7 @@ def read_codemodel_json_data(filename):
 def check_objects(o, g):
     assert is_list(o)
     assert len(o) == 1
-    check_index_object(o[0], "codemodel", 2, 6, check_object_codemodel(g))
+    check_index_object(o[0], "codemodel", 2, 7, check_object_codemodel(g))
 
 def check_backtrace(t, b, backtrace):
     btg = t["backtraceGraph"]
@@ -405,6 +405,27 @@ def check_target(c):
                              missing_exception=lambda e: "Install path: %s" % e["path"],
                              extra_exception=lambda a: "Install path: %s" % a["path"])
 
+        if "launchers" in expected:
+            if expected["launchers"] is not None:
+                expected_keys.append("launchers")
+                def check_launcher(actual, expected):
+                    assert is_dict(actual)
+                    launcher_keys = ["arguments", "command", "type"]
+                    assert sorted(actual.keys()) == sorted(launcher_keys)
+                    assert matches(actual["command"], expected["command"])
+                    assert matches(actual["type"], expected["type"])
+                    if expected["arguments"] is not None:
+                        check_list_match(lambda a, e: matches(a, e),
+                                        actual["arguments"], expected["arguments"],
+                                        missing_exception=lambda e: "argument: %s" % e,
+                                        extra_exception=lambda a: "argument: %s" % actual["arguments"])
+                check_list_match(lambda a, e: matches(a["type"], e["type"]),
+                                obj["launchers"], expected["launchers"],
+                                check=check_launcher,
+                                check_exception=lambda a, e: "launchers: %s" % a,
+                                missing_exception=lambda e: "launchers: %s" % e,
+                                extra_exception=lambda a: "launchers: %s" % a)
+
         if expected["link"] is not None:
             expected_keys.append("link")
             assert is_dict(obj["link"])
@@ -709,6 +730,7 @@ def gen_check_directories(c, g):
         read_codemodel_json_data("directories/alias.json"),
         read_codemodel_json_data("directories/custom.json"),
         read_codemodel_json_data("directories/cxx.json"),
+        read_codemodel_json_data("directories/cxx.cross.json"),
         read_codemodel_json_data("directories/imported.json"),
         read_codemodel_json_data("directories/interface.json"),
         read_codemodel_json_data("directories/object.json"),
@@ -782,6 +804,8 @@ def gen_check_targets(c, g, inSource):
         read_codemodel_json_data("targets/zero_check_cxx.json"),
         read_codemodel_json_data("targets/cxx_lib.json"),
         read_codemodel_json_data("targets/cxx_exe.json"),
+        read_codemodel_json_data("targets/cxx_exe_cross_emulator.json"),
+        read_codemodel_json_data("targets/cxx_exe_cross_emulator_args.json"),
         read_codemodel_json_data("targets/cxx_standard_compile_feature_exe.json"),
         read_codemodel_json_data("targets/cxx_standard_exe.json"),
         read_codemodel_json_data("targets/cxx_shared_lib.json"),

+ 15 - 0
Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.cross.json

@@ -0,0 +1,15 @@
+{
+    "source": "^cxx/cross$",
+    "build": "^cxx/cross$",
+    "parentSource": "^cxx$",
+    "parentIndex": 2,
+    "childSources": null,
+    "targetIds": [
+        "^cxx_exe_cross_emulator::@ee4a268216d1f53c4e2e$",
+        "^cxx_exe_cross_emulator_args::@ee4a268216d1f53c4e2e$"
+    ],
+    "projectName": "Cxx",
+    "minimumCMakeVersion": "3.13",
+    "hasInstallRule": null,
+    "installers": []
+}

+ 3 - 1
Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.json

@@ -2,7 +2,9 @@
     "source": "^cxx$",
     "build": "^cxx$",
     "parentSource": "^\\.$",
-    "childSources": null,
+    "childSources": [
+        "^cxx/cross$"
+    ],
     "targetIds": [
         "^ALL_BUILD::@a56b12a3f5c0529fb296$",
         "^ZERO_CHECK::@a56b12a3f5c0529fb296$",

+ 4 - 1
Tests/RunCMake/FileAPI/codemodel-v2-data/projects/cxx.json

@@ -3,13 +3,16 @@
     "parentName": "codemodel-v2",
     "childNames": null,
     "directorySources": [
-        "^cxx$"
+        "^cxx$",
+        "^cxx/cross$"
     ],
     "targetIds": [
         "^ALL_BUILD::@a56b12a3f5c0529fb296$",
         "^ZERO_CHECK::@a56b12a3f5c0529fb296$",
         "^cxx_lib::@a56b12a3f5c0529fb296$",
         "^cxx_exe::@a56b12a3f5c0529fb296$",
+        "^cxx_exe_cross_emulator::@ee4a268216d1f53c4e2e$",
+        "^cxx_exe_cross_emulator_args::@ee4a268216d1f53c4e2e$",
         "^cxx_standard_compile_feature_exe::@a56b12a3f5c0529fb296$",
         "^cxx_standard_exe::@a56b12a3f5c0529fb296$",
         "^cxx_shared_lib::@a56b12a3f5c0529fb296$",

+ 8 - 0
Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_cxx.json

@@ -82,6 +82,14 @@
             "id": "^cxx_exe::@a56b12a3f5c0529fb296$",
             "backtrace": null
         },
+        {
+            "id": "^cxx_exe_cross_emulator::@ee4a268216d1f53c4e2e$",
+            "backtrace": null
+        },
+        {
+            "id": "^cxx_exe_cross_emulator_args::@ee4a268216d1f53c4e2e$",
+            "backtrace": null
+        },
         {
             "id": "^cxx_standard_compile_feature_exe::@a56b12a3f5c0529fb296$",
             "backtrace": null

+ 8 - 0
Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_top.json

@@ -122,6 +122,14 @@
             "id": "^cxx_exe::@a56b12a3f5c0529fb296$",
             "backtrace": null
         },
+        {
+            "id": "^cxx_exe_cross_emulator::@ee4a268216d1f53c4e2e$",
+            "backtrace": null
+        },
+        {
+            "id": "^cxx_exe_cross_emulator_args::@ee4a268216d1f53c4e2e$",
+            "backtrace": null
+        },
         {
             "id": "^cxx_standard_compile_feature_exe::@a56b12a3f5c0529fb296$",
             "backtrace": null

+ 106 - 0
Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_cross_emulator.json

@@ -0,0 +1,106 @@
+{
+    "name": "cxx_exe_cross_emulator",
+    "id": "^cxx_exe_cross_emulator::@ee4a268216d1f53c4e2e$",
+    "directorySource": "^cxx/cross$",
+    "projectName": "Cxx",
+    "type": "EXECUTABLE",
+    "isGeneratorProvided": null,
+    "fileSets": null,
+    "sources": [
+        {
+            "path": "^empty\\.cxx$",
+            "isGenerated": null,
+            "fileSetName": null,
+            "sourceGroupName": "Source Files",
+            "compileGroupLanguage": "CXX",
+            "backtrace": [
+                {
+                    "file": "^cxx/cross/CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "add_executable",
+                    "hasParent": true
+                },
+                {
+                    "file": "^cxx/cross/CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        }
+    ],
+    "sourceGroups": [
+        {
+            "name": "Source Files",
+            "sourcePaths": [
+                "^empty\\.cxx$"
+            ]
+        }
+    ],
+    "compileGroups": [
+        {
+            "language": "CXX",
+            "sourcePaths": [
+                "^empty\\.cxx$"
+            ],
+            "includes": null,
+            "frameworks": null,
+            "defines": null,
+            "compileCommandFragments": null
+        }
+    ],
+    "backtrace": [
+        {
+            "file": "^cxx/cross/CMakeLists\\.txt$",
+            "line": 3,
+            "command": "add_executable",
+            "hasParent": true
+        },
+        {
+            "file": "^cxx/cross/CMakeLists\\.txt$",
+            "line": null,
+            "command": null,
+            "hasParent": false
+        }
+    ],
+    "folder": null,
+    "nameOnDisk": "^cxx_exe_cross_emulator(\\.exe)?$",
+    "artifacts": [
+        {
+            "path": "^cxx/cross/((Debug|Release|RelWithDebInfo|MinSizeRel)/)?cxx_exe_cross_emulator(\\.exe)?$",
+            "_dllExtra": false
+        },
+        {
+            "path": "^cxx/cross/((Debug|Release|RelWithDebInfo|MinSizeRel)/)?cxx_exe_cross_emulator\\.pdb$",
+            "_dllExtra": true
+        }
+    ],
+    "build": "^cxx/cross$",
+    "source": "^cxx/cross$",
+    "install": null,
+    "launchers" : [
+        {
+            "arguments" : null,
+            "command": "^no-such-emulator(\\.exe)?$",
+            "type" : "emulator"
+        }
+    ],
+    "link": {
+        "language": "CXX",
+        "lto": null,
+        "commandFragments": [
+            {
+                "fragment" : ".*",
+                "role" : "flags",
+                "backtrace": null
+            }
+        ]
+    },
+    "archive": null,
+    "dependencies": [
+        {
+            "id": "^ZERO_CHECK::@6890427a1f51a3e7e1df$",
+            "backtrace": null
+        }
+    ]
+}

+ 109 - 0
Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_cross_emulator_args.json

@@ -0,0 +1,109 @@
+{
+    "name": "cxx_exe_cross_emulator_args",
+    "id": "^cxx_exe_cross_emulator_args::@ee4a268216d1f53c4e2e$",
+    "directorySource": "^cxx/cross$",
+    "projectName": "Cxx",
+    "type": "EXECUTABLE",
+    "isGeneratorProvided": null,
+    "fileSets": null,
+    "sources": [
+        {
+            "path": "^empty\\.cxx$",
+            "isGenerated": null,
+            "fileSetName": null,
+            "sourceGroupName": "Source Files",
+            "compileGroupLanguage": "CXX",
+            "backtrace": [
+                {
+                    "file": "^cxx/cross/CMakeLists\\.txt$",
+                    "line": 6,
+                    "command": "add_executable",
+                    "hasParent": true
+                },
+                {
+                    "file": "^cxx/cross/CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        }
+    ],
+    "sourceGroups": [
+        {
+            "name": "Source Files",
+            "sourcePaths": [
+                "^empty\\.cxx$"
+            ]
+        }
+    ],
+    "compileGroups": [
+        {
+            "language": "CXX",
+            "sourcePaths": [
+                "^empty\\.cxx$"
+            ],
+            "includes": null,
+            "frameworks": null,
+            "defines": null,
+            "compileCommandFragments": null
+        }
+    ],
+    "backtrace": [
+        {
+            "file": "^cxx/cross/CMakeLists\\.txt$",
+            "line": 6,
+            "command": "add_executable",
+            "hasParent": true
+        },
+        {
+            "file": "^cxx/cross/CMakeLists\\.txt$",
+            "line": null,
+            "command": null,
+            "hasParent": false
+        }
+    ],
+    "folder": null,
+    "nameOnDisk": "^cxx_exe_cross_emulator_args(\\.exe)?$",
+    "artifacts": [
+        {
+            "path": "^cxx/cross/((Debug|Release|RelWithDebInfo|MinSizeRel)/)?cxx_exe_cross_emulator_args(\\.exe)?$",
+            "_dllExtra": false
+        },
+        {
+            "path": "^cxx/cross/((Debug|Release|RelWithDebInfo|MinSizeRel)/)?cxx_exe_cross_emulator_args\\.pdb$",
+            "_dllExtra": true
+        }
+    ],
+    "build": "^cxx/cross$",
+    "source": "^cxx/cross$",
+    "install": null,
+    "launchers" : [
+        {
+            "arguments" : [
+                    "arg1",
+                    "arg2 with space"
+            ],
+            "command": "^no-such-emulator(\\.exe)?$",
+            "type" : "emulator"
+        }
+    ],
+    "link": {
+        "language": "CXX",
+        "lto": null,
+        "commandFragments": [
+            {
+                "fragment" : ".*",
+                "role" : "flags",
+                "backtrace": null
+            }
+        ]
+    },
+    "archive": null,
+    "dependencies": [
+        {
+            "id": "^ZERO_CHECK::@6890427a1f51a3e7e1df$",
+            "backtrace": null
+        }
+    ]
+}

+ 2 - 0
Tests/RunCMake/FileAPI/cxx/CMakeLists.txt

@@ -45,3 +45,5 @@ if(_rdeps)
     FRAMEWORK DESTINATION fw
     )
 endif()
+
+add_subdirectory(cross)

+ 7 - 0
Tests/RunCMake/FileAPI/cxx/cross/CMakeLists.txt

@@ -0,0 +1,7 @@
+# Cross-compiling is normally global.  Cover it without duplicating everything.
+set(CMAKE_CROSSCOMPILING 1)
+add_executable(cxx_exe_cross_emulator ../../empty.cxx)
+set_property(TARGET cxx_exe_cross_emulator PROPERTY CROSSCOMPILING_EMULATOR no-such-emulator)
+
+add_executable(cxx_exe_cross_emulator_args ../../empty.cxx)
+set_property(TARGET cxx_exe_cross_emulator_args PROPERTY CROSSCOMPILING_EMULATOR "no-such-emulator;arg1;arg2 with space")