diff --git a/.gitignore b/.gitignore index 7bf77adf4..01fafa5a9 100644 --- a/.gitignore +++ b/.gitignore @@ -142,6 +142,7 @@ GTAGS # auto-generated compilation database compile_commands.json +*.compile_commands.json nix-rust/target diff --git a/doc/manual/src/contributing/hacking.md b/doc/manual/src/contributing/hacking.md index 916ec3077..28ed49666 100644 --- a/doc/manual/src/contributing/hacking.md +++ b/doc/manual/src/contributing/hacking.md @@ -258,7 +258,7 @@ See [supported compilation environments](#compilation-environments) and instruct To use the LSP with your editor, you first need to [set up `clangd`](https://clangd.llvm.org/installation#project-setup) by running: ```console -make clean && bear -- make -j$NIX_BUILD_CORES default check install +make compile_commands.json ``` Configure your editor to use the `clangd` from the shell, either by running it inside the development shell, or by using [nix-direnv](https://github.com/nix-community/nix-direnv) and [the appropriate editor plugin](https://github.com/direnv/direnv/wiki#editor-integration). diff --git a/mk/compilation-database.mk b/mk/compilation-database.mk new file mode 100644 index 000000000..f69dc0de0 --- /dev/null +++ b/mk/compilation-database.mk @@ -0,0 +1,11 @@ +compile-commands-json-files := + +define write-compile-commands + _srcs := $$(sort $$(foreach src, $$($(1)_SOURCES), $$(src))) + + $(1)_COMPILE_COMMANDS_JSON := $$(addprefix $(buildprefix), $$(addsuffix .compile_commands.json, $$(basename $$(_srcs)))) + + compile-commands-json-files += $$($(1)_COMPILE_COMMANDS_JSON) + + clean-files += $$($(1)_COMPILE_COMMANDS_JSON) +endef diff --git a/mk/lib.mk b/mk/lib.mk index fe0add1c9..a002d823f 100644 --- a/mk/lib.mk +++ b/mk/lib.mk @@ -68,6 +68,7 @@ include mk/patterns.mk include mk/templates.mk include mk/cxx-big-literal.mk include mk/tests.mk +include mk/compilation-database.mk # Include all sub-Makefiles. @@ -97,6 +98,13 @@ $(foreach test-group, $(install-tests-groups), \ $(eval $(call run-test,$(test),$(install_test_init))) \ $(eval $(test-group).test-group: $(test).test))) +# Compilation database. +$(foreach lib, $(libraries), $(eval $(call write-compile-commands,$(lib)))) +$(foreach prog, $(programs), $(eval $(call write-compile-commands,$(prog)))) + +compile_commands.json: $(compile-commands-json-files) + @jq --slurp '.' $^ >$@ + # Include makefiles requiring built programs. $(foreach mf, $(makefiles-late), $(eval $(call include-sub-makefile,$(mf)))) diff --git a/mk/patterns.mk b/mk/patterns.mk index c81150260..4caa2039e 100644 --- a/mk/patterns.mk +++ b/mk/patterns.mk @@ -1,11 +1,41 @@ + +# These are the complete command lines we use to compile C and C++ files. +# - $< is the source file. +# - $1 is the object file to create. +CC_CMD=$(CC) -o $1 -c $< $(CPPFLAGS) $(GLOBAL_CFLAGS) $(CFLAGS) $($1_CFLAGS) -MMD -MF $(call filename-to-dep,$1) -MP +CXX_CMD=$(CXX) -o $1 -c $< $(CPPFLAGS) $(GLOBAL_CXXFLAGS_PCH) $(GLOBAL_CXXFLAGS) $(CXXFLAGS) $($1_CXXFLAGS) $(ERROR_SWITCH_ENUM) -MMD -MF $(call filename-to-dep,$1) -MP + +# We use COMPILE_COMMANDS_JSON_CMD to turn a compilation command (like CC_CMD +# or CXX_CMD above) into a comple_commands.json file. We rely on bash native +# word splitting to define the positional arguments. +# - $< is the source file being compiled. +COMPILE_COMMANDS_JSON_CMD=jq --null-input '{ directory: $$ENV.PWD, file: "$<", arguments: $$ARGS.positional }' --args -- + + $(buildprefix)%.o: %.cc @mkdir -p "$(dir $@)" - $(trace-cxx) $(CXX) -o $@ -c $< $(CPPFLAGS) $(GLOBAL_CXXFLAGS_PCH) $(GLOBAL_CXXFLAGS) $(CXXFLAGS) $($@_CXXFLAGS) $(ERROR_SWITCH_ENUM) -MMD -MF $(call filename-to-dep, $@) -MP + $(trace-cxx) $(call CXX_CMD,$@) $(buildprefix)%.o: %.cpp @mkdir -p "$(dir $@)" - $(trace-cxx) $(CXX) -o $@ -c $< $(CPPFLAGS) $(GLOBAL_CXXFLAGS_PCH) $(GLOBAL_CXXFLAGS) $(CXXFLAGS) $($@_CXXFLAGS) $(ERROR_SWITCH_ENUM) -MMD -MF $(call filename-to-dep, $@) -MP + $(trace-cxx) $(call CXX_CMD,$@) $(buildprefix)%.o: %.c @mkdir -p "$(dir $@)" - $(trace-cc) $(CC) -o $@ -c $< $(CPPFLAGS) $(GLOBAL_CFLAGS) $(CFLAGS) $($@_CFLAGS) -MMD -MF $(call filename-to-dep, $@) -MP + $(trace-cc) $(call CC_CMD,$@) + +# In the following we need to replace the .compile_commands.json extension in $@ with .o +# to make the object file. This is needed because CC_CMD and CXX_CMD do further expansions +# based on the object file name (i.e. *_CXXFLAGS and filename-to-dep). + +$(buildprefix)%.compile_commands.json: %.cc + @mkdir -p "$(dir $@)" + $(trace-jq) $(COMPILE_COMMANDS_JSON_CMD) $(call CXX_CMD,$(@:.compile_commands.json=.o)) > $@ + +$(buildprefix)%.compile_commands.json: %.cpp + @mkdir -p "$(dir $@)" + $(trace-jq) $(COMPILE_COMMANDS_JSON_CMD) $(call CXX_CMD,$(@:.compile_commands.json=.o)) > $@ + +$(buildprefix)%.compile_commands.json: %.c + @mkdir -p "$(dir $@)" + $(trace-jq) $(COMPILE_COMMANDS_JSON_CMD) $(call CC_CMD,$(@:.compile_commands.json=.o)) > $@ diff --git a/mk/tracing.mk b/mk/tracing.mk index 1fc5573d7..09db1e617 100644 --- a/mk/tracing.mk +++ b/mk/tracing.mk @@ -10,6 +10,8 @@ ifeq ($(V), 0) trace-install = @echo " INST " $@; trace-mkdir = @echo " MKDIR " $@; trace-test = @echo " TEST " $@; + trace-sh = @echo " SH " $@; + trace-jq = @echo " JQ " $@; suppress = @