fileapi: add codemodel v2

Start with v2 to distinguish it from server-mode v1.

Issue: #18398
This commit is contained in:
Brad King 2018-10-18 09:39:25 -04:00
parent 555fa77a35
commit 3e922ceb5e
16 changed files with 1731 additions and 2 deletions

View File

@ -399,3 +399,473 @@ The ``kind`` member is a string specifying the object kind name.
The ``version`` member is a JSON object with ``major`` and ``minor``
members specifying integer components of the object kind's version.
Additional top-level members are specific to each object kind.
Object Kind "codemodel"
-----------------------
The ``codemodel`` object kind describes the build system structure as
modeled by CMake.
There is only one ``codemodel`` object major version, version 2.
Version 1 does not exist to avoid confusion with that from
:manual:`cmake-server(7)` mode.
"codemodel" version 2
^^^^^^^^^^^^^^^^^^^^^
``codemodel`` object version 2 is a JSON object:
.. code-block:: json
{
"kind": "codemodel",
"version": { "major": 2, "minor": 0 },
"paths": {
"source": "/path/to/top-level-source-dir",
"build": "/path/to/top-level-build-dir"
},
"configurations": [
{
"name": "Debug",
"directories": [
{
"source": ".",
"build": ".",
"childIndexes": [ 1 ],
"targetIndexes": [ 0 ]
},
{
"source": "sub",
"build": "sub",
"parentIndex": 0,
"targetIndexes": [ 1 ]
}
],
"targets": [
{
"name": "MyExecutable",
"directoryIndex": 0,
"jsonFile": "<file>"
},
{
"name": "MyLibrary",
"directoryIndex": 1,
"jsonFile": "<file>"
}
]
}
]
}
The members specific to ``codemodel`` objects are:
``paths``
A JSON object containing members:
``source``
A string specifying the absolute path to the top-level source directory,
represented with forward slashes.
``build``
A string specifying the absolute path to the top-level build directory,
represented with forward slashes.
``configurations``
A JSON array of entries corresponding to available build configurations.
On single-configuration generators there is one entry for the value
of the :variable:`CMAKE_BUILD_TYPE` variable. For multi-configuration
generators there is an entry for each configuration listed in the
:variable:`CMAKE_CONFIGURATION_TYPES` variable.
Each entry is a JSON object containing members:
``name``
A string specifying the name of the configuration, e.g. ``Debug``.
``directories``
A JSON array of entries each corresponding to a build system directory
whose source directory contains a ``CMakeLists.txt`` file. The first
entry corresponds to the top-level directory. Each entry is a
JSON object containing members:
``source``
A string specifying the path to the source directory, represented
with forward slashes. If the directory is inside the top-level
source directory then the path is specified relative to that
directory (with ``.`` for the top-level source directory itself).
Otherwise the path is absolute.
``build``
A string specifying the path to the build directory, represented
with forward slashes. If the directory is inside the top-level
build directory then the path is specified relative to that
directory (with ``.`` for the top-level build directory itself).
Otherwise the path is absolute.
``parentIndex``
Optional member that is present when the directory is not top-level.
The value is an unsigned integer 0-based index of another entry in
the main ``directories`` array that corresponds to the parent
directory that added this directory as a subdirectory.
``childIndexes``
Optional member that is present when the directory has subdirectories.
The value is a JSON array of entries corresponding to child directories
created by the :command:`add_subdirectory` or :command:`subdirs`
command. Each entry is an unsigned integer 0-based index of another
entry in the main ``directories`` array.
``targetIndexes``
Optional member that is present when the directory itself has targets,
excluding those belonging to subdirectories. The value is a JSON
array of entries corresponding to the targets. Each entry is an
unsigned integer 0-based index into the main ``targets`` array.
``targets``
A JSON array of entries corresponding to the build system targets.
Such targets are created by calls to :command:`add_executable`,
:command:`add_library`, and :command:`add_custom_target`, excluding
imported targets and interface libraries (which do not generate any
build rules). Each entry is a JSON object containing members:
``name``
A string specifying the target name.
``id``
A string uniquely identifying the target. This matches the ``id``
field in the file referenced by ``jsonFile``.
``directoryIndex``
An unsigned integer 0-based index into the main ``directories`` array
indicating the build system directory in which the target is defined.
``jsonFile``
A JSON string specifying a path relative to the codemodel file
to another JSON file containing a
`"codemodel" version 2 "target" object`_.
"codemodel" version 2 "target" object
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A codemodel "target" object is referenced by a `"codemodel" version 2`_
object's ``targets`` array. Each "target" object is a JSON object
with members:
``name``
A string specifying the logical name of the target.
``id``
A string uniquely identifying the target. The format is unspecified
and should not be interpreted by clients.
``type``
A string specifying the type of the target. The value is one of
``EXECUTABLE``, ``STATIC_LIBRARY``, ``SHARED_LIBRARY``,
``MODULE_LIBRARY``, ``OBJECT_LIBRARY``, or ``UTILITY``.
``backtrace``
Optional member that is present when a CMake language backtrace to
the command in the source code that created the target is available.
The value is an unsigned integer 0-based index into the
``backtraceGraph`` member's ``nodes`` array.
``folder``
Optional member that is present when the :prop_tgt:`FOLDER` target
property is set. The value is a JSON object with one member:
``name``
A string specifying the name of the target folder.
``paths``
A JSON object containing members:
``source``
A string specifying the path to the target's source directory,
represented with forward slashes. If the directory is inside the
top-level source directory then the path is specified relative to
that directory (with ``.`` for the top-level source directory itself).
Otherwise the path is absolute.
``build``
A string specifying the path to the target's build directory,
represented with forward slashes. If the directory is inside the
top-level build directory then the path is specified relative to
that directory (with ``.`` for the top-level build directory itself).
Otherwise the path is absolute.
``nameOnDisk``
Optional member that is present for executable and library targets
that are linked or archived into a single primary artifact.
The value is a string specifying the file name of that artifact on disk.
``artifacts``
Optional member that is present for executable and library targets
that produce artifacts on disk meant for consumption by dependents.
The value is a JSON array of entries corresponding to the artifacts.
Each entry is a JSON object containing one member:
``path``
A string specifying the path to the file on disk, represented with
forward slashes. If the file is inside the top-level build directory
then the path is specified relative to that directory.
Otherwise the path is absolute.
``isGeneratorProvided``
Optional member that is present with boolean value ``true`` if the
target is provided by CMake's build system generator rather than by
a command in the source code.
``install``
Optional member that is present when the target has an :command:`install`
rule. The value is a JSON object with members:
``prefix``
A JSON object specifying the installation prefix. It has one member:
``path``
A string specifying the value of :variable:`CMAKE_INSTALL_PREFIX`.
``destinations``
A JSON array of entries specifying an install destination path.
Each entry is a JSON object with members:
``path``
A string specifying the install destination path. The path may
be absolute or relative to the install prefix.
``backtrace``
Optional member that is present when a CMake language backtrace to
the :command:`install` command invocation that specified this
destination is available. The value is an unsigned integer 0-based
index into the ``backtraceGraph`` member's ``nodes`` array.
``link``
Optional member that is present for executables and shared library
targets that link into a runtime binary. The value is a JSON object
with members describing the link step:
``language``
A string specifying the language (e.g. ``C``, ``CXX``, ``Fortran``)
of the toolchain is used to invoke the linker.
``commandFragments``
Optional member that is present when fragments of the link command
line invocation are available. The value is a JSON array of entries
specifying ordered fragments. Each entry is a JSON object with members:
``fragment``
A string specifying a fragment of the link command line invocation.
The value is encoded in the build system's native shell format.
``role``
A string specifying the role of the fragment's content:
* ``flags``: link flags.
* ``libraries``: link library file paths or flags.
* ``libraryPath``: library search path flags.
* ``frameworkPath``: macOS framework search path flags.
``lto``
Optional member that is present with boolean value ``true``
when link-time optimization (a.k.a. interprocedural optimization
or link-time code generation) is enabled.
``sysroot``
Optional member that is present when the :variable:`CMAKE_SYSROOT_LINK`
or :variable:`CMAKE_SYSROOT` variable is defined. The value is a
JSON object with one member:
``path``
A string specifying the absolute path to the sysroot, represented
with forward slashes.
``archive``
Optional member that is present for static library targets. The value
is a JSON object with members describing the archive step:
``commandFragments``
Optional member that is present when fragments of the archiver command
line invocation are available. The value is a JSON array of entries
specifying the fragments. Each entry is a JSON object with members:
``fragment``
A string specifying a fragment of the archiver command line invocation.
The value is encoded in the build system's native shell format.
``role``
A string specifying the role of the fragment's content:
* ``flags``: archiver flags.
``lto``
Optional member that is present with boolean value ``true``
when link-time optimization (a.k.a. interprocedural optimization
or link-time code generation) is enabled.
``dependencies``
Optional member that is present when the target depends on other targets.
The value is a JSON array of entries corresponding to the dependencies.
Each entry is a JSON object with members:
``id``
A string uniquely identifying the target on which this target depends.
This matches the main ``id`` member of the other target.
``backtrace``
Optional member that is present when a CMake language backtrace to
the :command:`add_dependencies`, :command:`target_link_libraries`,
or other command invocation that created this dependency is
available. The value is an unsigned integer 0-based index into
the ``backtraceGraph`` member's ``nodes`` array.
``sources``
A JSON array of entries corresponding to the target's source files.
Each entry is a JSON object with members:
``path``
A string specifying the path to the source file 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.
Otherwise the path is absolute.
``compileGroupIndex``
Optional member that is present when the source is compiled.
The value is an unsigned integer 0-based index into the
``compileGroups`` array.
``sourceGroupIndex``
Optional member that is present when the source is part of a source
group either via the :command:`source_group` command or by default.
The value is an unsigned integer 0-based index into the
``sourceGroups`` array.
``isGenerated``
Optional member that is present with boolean value ``true`` if
the source is :prop_sf:`GENERATED`.
``backtrace``
Optional member that is present when a CMake language backtrace to
the :command:`target_sources`, :command:`add_executable`,
:command:`add_library`, :command:`add_custom_target`, or other
command invocation that added this source to the target is
available. The value is an unsigned integer 0-based index into
the ``backtraceGraph`` member's ``nodes`` array.
``sourceGroups``
Optional member that is present when sources are grouped together by
the :command:`source_group` command or by default. The value is a
JSON array of entries corresponding to the groups. Each entry is
a JSON object with members:
``name``
A string specifying the name of the source group.
``sourceIndexes``
A JSON array listing the sources belonging to the group.
Each entry is an unsigned integer 0-based index into the
main ``sources`` array for the target.
``compileGroups``
Optional member that is present when the target has sources that compile.
The value is a JSON array of entries corresponding to groups of sources
that all compile with the same settings. Each entry is a JSON object
with members:
``sourceIndexes``
A JSON array listing the sources belonging to the group.
Each entry is an unsigned integer 0-based index into the
main ``sources`` array for the target.
``language``
A string specifying the language (e.g. ``C``, ``CXX``, ``Fortran``)
of the toolchain is used to compile the source file.
``compileCommandFragments``
Optional member that is present when fragments of the compiler command
line invocation are available. The value is a JSON array of entries
specifying ordered fragments. Each entry is a JSON object with
one member:
``fragment``
A string specifying a fragment of the compile command line invocation.
The value is encoded in the build system's native shell format.
``includes``
Optional member that is present when there are include directories.
The value is a JSON array with an entry for each directory. Each
entry is a JSON object with members:
``path``
A string specifying the path to the include directory,
represented with forward slashes.
``isSystem``
Optional member that is present with boolean value ``true`` if
the include directory is marked as a system include directory.
``backtrace``
Optional member that is present when a CMake language backtrace to
the :command:`target_include_directories` or other command invocation
that added this include directory is available. The value is
an unsigned integer 0-based index into the ``backtraceGraph``
member's ``nodes`` array.
``defines``
Optional member that is present when there are preprocessor definitions.
The value is a JSON array with an entry for each definition. Each
entry is a JSON object with members:
``define``
A string specifying the preprocessor definition in the format
``<name>[=<value>]``, e.g. ``DEF`` or ``DEF=1``.
``backtrace``
Optional member that is present when a CMake language backtrace to
the :command:`target_compile_definitions` or other command invocation
that added this preprocessor definition is available. The value is
an unsigned integer 0-based index into the ``backtraceGraph``
member's ``nodes`` array.
``sysroot``
Optional member that is present when the
:variable:`CMAKE_SYSROOT_COMPILE` or :variable:`CMAKE_SYSROOT`
variable is defined. The value is a JSON object with one member:
``path``
A string specifying the absolute path to the sysroot, represented
with forward slashes.
``backtraceGraph``
A JSON object describing the graph of backtraces whose nodes are
referenced from ``backtrace`` members elsewhere. The members are:
``nodes``
A JSON array listing nodes in the backtrace graph. Each entry
is a JSON object with members:
``file``
An unsigned integer 0-based index into the backtrace ``files`` array.
``line``
An optional member present when the node represents a line within
the file. The value is an unsigned integer 1-based line number.
``command``
An optional member present when the node represents a command
invocation within the file. The value is an unsigned integer
0-based index into the backtrace ``commands`` array.
``parent``
An optional member present when the node is not the bottom of
the call stack. The value is an unsigned integer 0-based index
of another entry in the backtrace ``nodes`` array.
``commands``
A JSON array listing command names referenced by backtrace nodes.
Each entry is a string specifying a command name.
``files``
A JSON array listing CMake language files referenced by backtrace nodes.
Each entry is a string specifying the path to a file, represented
with forward slashes. If the file is inside the top-level source
directory then the path is specified relative to that directory.
Otherwise the path is absolute.

View File

@ -209,6 +209,8 @@ set(SRCS
cmExtraSublimeTextGenerator.h
cmFileAPI.cxx
cmFileAPI.h
cmFileAPICodemodel.cxx
cmFileAPICodemodel.h
cmFileLock.cxx
cmFileLock.h
cmFileLockPool.cxx

View File

@ -4,6 +4,7 @@
#include "cmAlgorithms.h"
#include "cmCryptoHash.h"
#include "cmFileAPICodemodel.h"
#include "cmGlobalGenerator.h"
#include "cmSystemTools.h"
#include "cmTimestamp.h"
@ -224,6 +225,17 @@ bool cmFileAPI::ReadQuery(std::string const& query,
}
std::string kindName = query.substr(0, sep_pos);
std::string verStr = query.substr(sep_pos + 1);
if (kindName == ObjectKindName(ObjectKind::CodeModel)) {
Object o;
o.Kind = ObjectKind::CodeModel;
if (verStr == "v2") {
o.Version = 2;
} else {
return false;
}
objects.push_back(o);
return true;
}
if (kindName == ObjectKindName(ObjectKind::InternalTest)) {
Object o;
o.Kind = ObjectKind::InternalTest;
@ -361,7 +373,8 @@ const char* cmFileAPI::ObjectKindName(ObjectKind kind)
{
// Keep in sync with ObjectKind enum.
static const char* objectKindNames[] = {
"__test" //
"codemodel", //
"__test" //
};
return objectKindNames[size_t(kind)];
}
@ -379,6 +392,9 @@ Json::Value cmFileAPI::BuildObject(Object const& object)
Json::Value value;
switch (object.Kind) {
case ObjectKind::CodeModel:
value = this->BuildCodeModel(object);
break;
case ObjectKind::InternalTest:
value = this->BuildInternalTest(object);
break;
@ -429,7 +445,9 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest(
}
std::string const& kindName = kind.asString();
if (kindName == this->ObjectKindName(ObjectKind::InternalTest)) {
if (kindName == this->ObjectKindName(ObjectKind::CodeModel)) {
r.Kind = ObjectKind::CodeModel;
} else if (kindName == this->ObjectKindName(ObjectKind::InternalTest)) {
r.Kind = ObjectKind::InternalTest;
} else {
r.Error = "unknown request kind '" + kindName + "'";
@ -447,6 +465,9 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest(
}
switch (r.Kind) {
case ObjectKind::CodeModel:
this->BuildClientRequestCodeModel(r, versions);
break;
case ObjectKind::InternalTest:
this->BuildClientRequestInternalTest(r, versions);
break;
@ -592,6 +613,42 @@ std::string cmFileAPI::NoSupportedVersion(
return msg.str();
}
// The "codemodel" object kind.
static unsigned int const CodeModelV2Minor = 0;
void cmFileAPI::BuildClientRequestCodeModel(
ClientRequest& r, std::vector<RequestVersion> const& versions)
{
// Select a known version from those requested.
for (RequestVersion const& v : versions) {
if ((v.Major == 2 && v.Minor <= CodeModelV2Minor)) {
r.Version = v.Major;
break;
}
}
if (!r.Version) {
r.Error = NoSupportedVersion(versions);
}
}
Json::Value cmFileAPI::BuildCodeModel(Object const& object)
{
using namespace std::placeholders;
Json::Value codemodel = cmFileAPICodemodelDump(*this, object.Version);
codemodel["kind"] = this->ObjectKindName(object.Kind);
Json::Value& version = codemodel["version"] = Json::objectValue;
if (object.Version == 2) {
version["major"] = 2;
version["minor"] = CodeModelV2Minor;
} else {
return codemodel; // should be unreachable
}
return codemodel;
}
// The "__test" object kind is for internal testing of CMake.
static unsigned int const InternalTestV1Minor = 3;

View File

@ -51,6 +51,7 @@ private:
// Keep in sync with ObjectKindName.
enum class ObjectKind
{
CodeModel,
InternalTest
};
@ -181,6 +182,10 @@ private:
static std::string NoSupportedVersion(
std::vector<RequestVersion> const& versions);
void BuildClientRequestCodeModel(
ClientRequest& r, std::vector<RequestVersion> const& versions);
Json::Value BuildCodeModel(Object const& object);
void BuildClientRequestInternalTest(
ClientRequest& r, std::vector<RequestVersion> const& versions);
Json::Value BuildInternalTest(Object const& object);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmFileAPICodemodel_h
#define cmFileAPICodemodel_h
#include "cmConfigure.h" // IWYU pragma: keep
#include "cm_jsoncpp_value.h"
class cmFileAPI;
extern Json::Value cmFileAPICodemodelDump(cmFileAPI& fileAPI,
unsigned long version);
#endif

View File

@ -43,3 +43,14 @@ run_cmake(ClientStateless)
run_cmake(MixedStateless)
run_cmake(DuplicateStateless)
run_cmake(ClientStateful)
function(run_object object)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${object}-build)
run_cmake(${object})
set(RunCMake_TEST_NO_CLEAN 1)
run_cmake_command(${object}-SharedStateless ${CMAKE_COMMAND} .)
run_cmake_command(${object}-ClientStateless ${CMAKE_COMMAND} .)
run_cmake_command(${object}-ClientStateful ${CMAKE_COMMAND} .)
endfunction()
run_object(codemodel-v2)

View File

@ -0,0 +1,11 @@
set(expect
query
query/client-foo
query/client-foo/query.json
reply
reply/codemodel-v2-[0-9a-f]+.json
reply/index-[0-9.T-]+.json
)
check_api("^${expect}$")
check_python(codemodel-v2)

View File

@ -0,0 +1,4 @@
file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/query.json" [[
{ "requests": [ { "kind": "codemodel", "version" : 2 } ] }
]])

View File

@ -0,0 +1,11 @@
set(expect
query
query/client-foo
query/client-foo/codemodel-v2
reply
reply/codemodel-v2-[0-9a-f]+.json
reply/index-[0-9.T-]+.json
)
check_api("^${expect}$")
check_python(codemodel-v2)

View File

@ -0,0 +1,2 @@
file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/codemodel-v2" "")

View File

@ -0,0 +1,10 @@
set(expect
query
query/codemodel-v2
reply
reply/codemodel-v2-[0-9a-f]+.json
reply/index-[0-9.T-]+.json
)
check_api("^${expect}$")
check_python(codemodel-v2)

View File

@ -0,0 +1,2 @@
file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/codemodel-v2" "")

View File

@ -0,0 +1,15 @@
from check_index import *
def check_objects(o):
assert is_list(o)
assert len(o) == 1
check_index_object(o[0], "codemodel", 2, 0, check_object_codemodel)
def check_object_codemodel(o):
assert sorted(o.keys()) == ["configurations", "kind", "paths", "version"]
# The "kind" and "version" members are handled by check_index_object.
# FIXME: Check "configurations" and "paths" members
assert is_dict(index)
assert sorted(index.keys()) == ["cmake", "objects", "reply"]
check_objects(index["objects"])

View File

@ -0,0 +1 @@
# FIXME: enable_language(C) and add targets to dump

View File

@ -126,6 +126,8 @@
{ symbol: [ "SIGINT", private, "\"cm_uv.h\"", public ] },
{ symbol: [ "ssize_t", private, "\"cm_uv.h\"", public ] },
{ symbol: [ "Json::ArrayIndex", private, "\"cm_jsoncpp_value.h\"", public ] },
{ symbol: [ "std::ifstream", private, "\"cmsys/FStream.hxx\"", public ] },
{ symbol: [ "std::ofstream", private, "\"cmsys/FStream.hxx\"", public ] },
{ symbol: [ "cmsys::ifstream", private, "\"cmsys/FStream.hxx\"", public ] },