Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

C/C++ language server implemented on top of Clang frontend.

License

NotificationsYou must be signed in to change notification settings

JBakamovic/cxxd

Repository files navigation

About

cxxd is a C/C++ language server which offers rich support for features that aid the process of source code navigation, editing, source code formatting, static analysis etc. One can utilize it, for example, to bring IDE-like features to an editor of your choice.

Feature overview

FeatureStatuscxxd-vim frontend
Indexer✔️✔️
Indexer-diagnostics✔️✔️
Code-completion✔️✔️
Semantic-syntax-highlighting✔️✔️
Find-all-references✔️✔️
Go-to-definition✔️✔️
Go-to-include✔️✔️
Type-hints✔️✔️
Fixits-and-diagnostics✔️✔️
Clang-tidy integration✔️✔️
Clang-format integration✔️✔️
JSON-compilation-database integration✔️✔️
Plain-text-compilation-database integration✔️✔️
Arbitrary build targets integration✔️✔️
Per-repository cxxd custom configuration (JSON)✔️✔️
Godbolt-like disassembler✔️✔️

In essence, the main idea behind it is very much alike to whatLSP offersand its implementations likeclangd.

Supported platforms

PlatformStatusComments
Linux✔️Main development environment of this project.
Other platformsNot officially tested but should work whereverpython3 andlibclang is available

Supported frontends (editors)

EditorLinkDescription
Vimcxxd-vimA PoC Vim plugin integration that I did for this project and which became my daily driver since then.

Dependencies

Required:Python3,libclang (withPython bindings)

Optional:clang-format,clang-tidy

PlatformInstall
Fedorasudo dnf install python3 clang-devel clang-libs clang-tools-extra && pip install --user clang cxxfilt
Debiansudo apt-get install python3 libclang-dev clang-tidy clang-format && pip install --user clang cxxfilt

Configuration

To runcxxd server against the source code one should provide.cxxd_config.json configuration file and put it into the root of the project repository.

This file can be used to provide project-specific configurations such as:

CategoryTypeValueDescription
configurationcxxd at the bare minimum requires eithercompile_commands.json orcompile_flags.txt to be provided with the project.
.typecompilation-database,compile-flags,auto-discoveryDepending on how do you want to runcxxd server against your project select one of those options. Whilecompilation-database is the most recommended way which should be used for real-world projects,compile-flags is provided only for convenience purposes and should be used only for a very simple and small projects. Withauto-discovery option,cxxd will try to figure out itself what type of configuration is project using. If notype is provided thencxxd will fallback to implicitauto-discovery-try-harder mode.
.compilation-databasetarget : { build-target1:build-dir1, ..., build-targetN:build-dirN}Real-world projects will have different build target configurations andtarget field can be used to define a list of relevant build targets and their accompanying build directories. E.g.compilation-database : { target : { 'debug': 'build/debug', 'relwithdebinfo': 'build/relwithdebinfo', 'debug-asan': 'build/debug-asan'}}
.compile-flagsSame as withcompilation-database option.Same as withcompilation-database option.
.auto-discoverysearch-paths: [list of directories]Cannot be used for defining arbitrary build targets. Provided only as a quickstart convenience method. Usesearch-paths field to provide a list of directories wherecxxd will look forcompile_commands.json orcompile_flags.txt. If not providedcxxd will use some of the implicitly predefined search paths.
project-builderTo make use of previously defined build-targets fromconfiguration::compilation-database orconfiguration::compile-flags here we can define the actual build commands to be run bycxxd server.
.targettarget : { build-target1: { cmd: build-target1-specific-build-cmd }, ..., build-targetN: {cmd: build-targetN-specific-build-cmd}Mind that build-target names used here must match the build-target names used inconfiguration::compilation-database orconfiguration::compile-flags. Example of build-target commands:target : { 'debug': 'cmake . -GNinja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache && ninja', 'relwithdebinfo': 'cmake . -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache && ninja', 'debug-asan': 'cmake . -GNinja -DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache && ninja'}}. You can add any amount of arbitrary build target commands here.
indexerSource-code indexing related settings.
.exclude-dirsA list of directoriesUsed as a hint tocxxd indexer to exclude certain from being indexed. Commonly these can be directories such asbuild,cmake,external,third-party etc.
.extra-file-extensionsA list of file extensionsUsed as a hint tocxxd indexer to also index files with non-standard C or C++ extensions that your project might be using.cxxd will try hard to implicitly identify most of the non-standard C and C++ extensions found in the wild but in case it doesn't, this is a setting for it.
clang-formatHere we can customize how we want to useclang-format for given repository.
.binarypath-to-specific-clang-format-binarySometimes system-wide installedclang-format version will not match the needs of real-world projects. It can be either too old or too recent. This setting allows to set the specific version ofclang-format binary provided that the one exists in the given path. E.g.'binary': '/opt/clang+llvm-8.0.0-x86_64-linux-gnu/bin/clang-format'.
.argsclang-format specific cmd-line argsHere we can provide a list of any arguments that we want to pass over toclang-format invocation. For example, applyingclang-format immediatelly and in-place following theclang-format configuration hosted by our repository can be done with'args' : { '-i' : true, '--style' : 'file' }. We can use this list to basically pass any argument that given version ofclang-format can recognize and tweak it according to the project-specific needs.
clang-tidyHere we can customize how we want to useclang-tidy for given repository.
.binarypath-to-specific-clang-tidy-binarySometimes system-wide installedclang-tidy version will not match the needs of real-world projects. It can be either too old or too recent. This setting allows to set the specific version ofclang-tidy binary provided that the one exists in the given path. E.g.'binary': '/opt/clang+llvm-8.0.0-x86_64-linux-gnu/bin/clang-tidy'.
.argsclang-tidy specific cmd-line argsHere we can provide a list of any arguments that we want to pass over toclang-tidy invocation. For example, to enable bugprone, cppcoreguidelines and readabilityclang-tidy checks we would do'args' : { '-checks' : "'-*,bugprone-*,cppcoreguidelines-*,readability-*'", "-extra-arg" : "'-Wno-unknown-warning-option'", '-header-filter' : '.*' }. We can use this list to basically pass any argument that given version ofclang-tidy can recognize and tweak it according to the project-specific needs.
clangHere we can optionally set some of theclang-specific settings. Should be needed very rarely.
.library-filepath-to-specific-libclang-so-libraryWhen updating your system, sometimes a new version oflibclang can introduce bugs or changes in behavior which will result with glitches in the usage experience. Same can happen with the python bindings oflibclang. Becausecxxd does not have a capacity to be tested against every version oflibclang and its python bindings,library-file serves the purpose to tellcxxd to use a certain version oflibclang. If not provided,cxxd will by default use the system-wide one, which in most cases should be enough. However, if you suddenly start to experience the issues, which you have not before, this should be a first thing to check. And possibly revert thelibclang version to an earlier one. E.g.'library-file': '/usr/lib64/libclang.so.14.0.5'.
disassemblyGodbolt-like utility which allows you to examine the disassembly in selected executable target for a given symbol you requested it for at the source code level.
.objdump
.binarypath-to-specific-objdump-binaryUsually system-wide installedobjdump will match the needs but if not, this field can be used to pin to particular version ofobjdump. E.g.'binary': '/opt/clang+llvm-8.0.0-x86_64-linux-gnu/bin/objdump'
.intermix-with-src-codetrue or falseDefault is false. If you want to see source-code mixed within the disassembled binary set this field to true.
.visualize-jumpstrue or falseDefault is true. If you want to disable ASCII art which visualizes jumps within the disassembled binary set this field to false.
.syntaxintel orattDefault isintel. Syntax used for instructions in a disassembled binary.
.nm
.binarypath-to-specific-nm-binaryUsually system-wide installednm will match the needs but if not, this field can be used to pin to particular version ofnm. E.g.'binary': '/opt/clang+llvm-8.0.0-x86_64-linux-gnu/bin/nm'
.targets-filterA list of extensions or directoriesPrior to disassembly, a target binary needs to be selected. This filter can be used to remove targets that are not interesting. E.g.[".so", ".a", "CMake"]

Compilation database

Compilation database is a requirement forcxxd. It can come in two different forms:compile_commands.json (recommended) orcompile_flags.txt (should be used only as a fallback when generatingcompile_commands.json is not possible)

compile_commands.json

TL;DR in CMake projects you would simply add-DCMAKE_EXPORT_COMPILE_COMMANDS=ON to your CMake build invocation call. Or you could bake this setting into theCMakeLists.txt withset(CMAKE_EXPORT_COMPILE_COMMANDS ON). And you're done.

CMake/Bazel/waf/Qbs/ninja/clang have native and built-in support for generating this type of compilation database.Here's a good summary on how to use each of those. If you don't use any of those build systems, thensame page provides another good summary on how to try to generate the compilation database in alternative ways.

compile_flags.txt

If generating thecompile_commands.json is not possible to achieve within your environment, you can hand-code the build flags yourself and put it into the file namedcompile_flags.txt. E.g.

-I./lib-I./include-DFEATURE_XX-DFEATURE_YY-Wall-Werror

Example of configuration

For completness and quickstart sake here's an example of a config file that I used while hacking on the MySQL database engine at Oracle. You can use it as starting point to create your own.

I used out-of-source builds with plenty of different ways to build and test the code. My regular workflow included running both sanitized (ASAN, UBSAN) and non-sanitizeddebug orrelwithdebinfo builds. Sometimes I also had to test or backport the changes from MySQL 8.x to MySQL 5.x so I also had the build targets for that purpose. Later on I even tweaked the build target commands to include the way to run the build in distributed fashion throughdistcc andicecream.

clang-format version had to strictly adhere to specific version declared to be used by MySQL. Occassionally this version would be bumped so I also occassionally bumped the version in the config file.

Some parts of the MySQL used non-standard file extensions for the source code such as*.ic,.i or*.tpp. To make them visible to thecxxd indexer I have enumerated them in theextra-file-extensions field. Similarly, I have hinted thecxxd indexer not to index 3rd-party source code that is found inextra directory.

{    "configuration" : {        "type" : "compilation-database",        "compilation-database" : {            "target" : {                "debug" : "../build/trunk/debug",                "debug_asan" : "../build/trunk/debug_asan",                "debug_ubsan" : "../build/trunk/debug_ubsan",                "relwithdebinfo" : "../build/trunk/relwithdebinfo",                "relwithdebinfo_asan" : "../build/trunk/relwithdebinfo_asan",                "relwithdebinfo_ubsan" : "../build/trunk/relwithdebinfo_ubsan",                "debug5" : "../build/5.x/debug",                "relwithdebinfo5" : "../build/5.x/relwithdebinfo",             }        }    },    "indexer" : {        "exclude-dirs" : [            "extra"        ],        "extra-file-extensions" : [            ".ic",            ".i",            ".tpp"        ]    },    "clang-tidy" : {        "args" : {            "-checks" : "'-*,bugprone-*,cert-*,clang-analyzer-*,-clang-analyzer-osx*,misc-*,performance-*,portability-*,readability-*",            "-extra-arg" : "'-Wno-unknown-warning-option'",            "-header-filter" : ".*"        }    },    "clang-format" : {        "binary" : "/opt/clang+llvm-8.0.0-x86_64-linux-gnu/bin/clang-format",        "args" : {            "-i" : true,            "--style" : "file"        }    },    "project-builder" : {        "target" : {            "debug" : {                "cmd" : "cmake ../../../trunk -GNinja -DCMAKE_BUILD_TYPE=Debug -DDOWNLOAD_BOOST=ON -DWITH_BOOST=../ -DWITH_UNIT_TESTS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache && ninja"            },            "debug_asan" : {                "cmd" : "cmake ../../../trunk -GNinja -DCMAKE_BUILD_TYPE=Debug -DDOWNLOAD_BOOST=ON -DWITH_BOOST=../ -DWITH_UNIT_TESTS=ON -DWITH_ASAN=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache && ninja"            },            "debug_ubsan" : {                "cmd" : "cmake ../../../trunk -GNinja -DCMAKE_BUILD_TYPE=Debug -DDOWNLOAD_BOOST=ON -DWITH_BOOST=../ -DWITH_UNIT_TESTS=ON -DWITH_UBSAN=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache && ninja"            },            "relwithdebinfo" : {                "cmd" : "cmake ../../../trunk -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DDOWNLOAD_BOOST=ON -DWITH_BOOST=../ -DWITH_UNIT_TESTS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache && ninja"            },            "relwithdebinfo_asan" : {                "cmd" : "cmake ../../../trunk -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DDOWNLOAD_BOOST=ON -DWITH_BOOST=../ -DWITH_UNIT_TESTS=ON -DWITH_ASAN=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache && ninja"            },            "relwithdebinfo_ubsan" : {                "cmd" : "cmake ../../../trunk -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DDOWNLOAD_BOOST=ON -DWITH_BOOST=../ -DWITH_UNIT_TESTS=ON -DWITH_UBSAN=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache && ninja"            },            "debug5" : {                "cmd" : "cmake ../../../5.x -GNinja -DCMAKE_BUILD_TYPE=Debug -DDOWNLOAD_BOOST=ON -DWITH_BOOST=../ -DWITH_UNIT_TESTS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache && ninja"            },            "relwithdebinfo5" : {                "cmd" : "cmake ../../../5.x -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DDOWNLOAD_BOOST=ON -DWITH_BOOST=../ -DWITH_UNIT_TESTS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache && ninja"            },        }    },    "disassembly" : {        "objdump" : {            "intermix-with-src-code" : false,            "visualize-jumps" : true,            "syntax" : "intel"        },        "nm" : {        },        "targets-filter" : [".so", ".a", "CMake"]    }}

FAQ

How do I make use of this in <insert_environment_of_your_choice>?

Currently there's only a Vimcxxd-vim plugin that I have developed as a PoC and which I have been using as my daily driver since then. On a semi-regular base I try to keep it up to date with the bugfixes and less often with the new features.

To integratecxxd with another editor one should read through thearchitecture overview. Also, file a ticket if you need help.

What about clangd and other language server implementations

Fun fact: this project actually started to grow thewhole idea and implementationbeforeLSP (and clangd) has been put into life. And I am basically hacking oncxxd andcxxd-vim codebase since then. But I do it only occassionaly and as much as my spare time allows me to.

It turns out that writing a language server implementation on top of thelibclang backend is a mine field. Complex C and C++ compilation process doesn't make this situation any easier. Variety of build systems available and multitude of different ways on how you can build a model of your code due to arbitary number of build targets also makes it a bigger challenge. And only because I implemented both the language server side and the UI frontend side that accompanies it, and everything from the scratch, it happens that I find it easier (and more fun!) to hack through my own codebase and learning something new rather than waiting on other similar tools to provide the fixes, if at all. I tried many of them and they all experience from same or similar issues I stumble upon as well. YMMV of course.

I also implemented a non-LSP compatible protocol which means that I am free to decide and integrate whatever I find interesting for a development workflow. One such example is support for arbitrary build targets which happens to have an actual impact on how the language server backend will understand your code or will not. Browsing or indexing or code-completion context isn't the same across "debug" or "debug-with-some-fancy-feature" or "relwithdebinfo" targets. For that reason,cxxd is always started against the specific build target.

Screenshots

To see how it looks like in action you may have a look at thescreenshots from cxxd-vim.

Releases

No releases published

Packages

No packages published

Languages


[8]ページ先頭

©2009-2025 Movatter.jp