Work on existing project with multiple sub-projects in chrooted environment
I am working on a project laid out like this:
Workspace
+ build
| +
+ src
+ main_project
| + CMakeLists.txt
| + (...)
+ sub_project_1
| + CMakeLists.txt
| + (...)
(...)
All of my toolchain is available from a custom environment that I need to get into (more or less chroot + mounting directories + other stuff). To avoid further headaches, I have the same username on the inside and outside, I mount my host home to /mnt/<username>, and symlink /mnt/<username>/Workspace to /home/<username>/Workspace inside the chroot. This way, the directory tree looks the same either way.
How I build it right now (pure command line)
1) Run the program that does the chroot.
2) Create directory Workspace/build if it doesn't exist.
2) > cd Workspace/build
3) > cmake <OPTIONS> ../src/main_project
4) > make <TARGET1> <TARGET2> ... <OPTIONS>
The cmake project is configured to download all the necessary sub-projects as necessary.
How would I like to build it (using CLion)
1) Open the whole Workspace in the project window and have access to all of the sub-projects.
2) Preferably, have all CLion-specific files right under Workspace/ and not inside Workspace/src/main_project
3) Generate Workspace/build as necessary.
4) Build targets as chosen.
What I managed to do
1) I made a script that runs cmake in the chrooted environment and passes arguments to it.
2) I set up a toolchain that used said script in place of regular cmake.
3) I set the generation path in "Build, Execution, Deployment / CMake" to Workspace/build
4) I click on the CMakeLists.txt from the main project, and select "Reload CMake project"
What doesn't work + my workarounds
1) I managed to get CLion to work in the Workspace directory by making a dummy toplevel project in Workspace/CMakeLists.txt, then adding subdirectories until I got to the main project.
2) If I run my cmake-running script as-is, I get the following error:
CMake Error: The source "/home/<me>/Workspace/src/<main_project>/CMakeLists.txt" does not match the source "/tmp/cmake_check_environment/CMakeLists.txt" used to generate cache
I fixed this by cd-ing to Workspace/build before running cmake, however I'm not sure how would it handle multiple build types (debug/release).
3) I cannot build from CLion. I don't see any targets, and I just run "Rebuild project" I get
"Cannot find any CMake profile"
I can, however, build by manually running make in the directory generated by CLion.
4) "Go to definition" etc. doesn't work outside a single file.
Perhaps I didn't set up the project correctly in (1), but I'm not sure how to do it better, I'm new to both CMake and CLion.
TL;DR
After banging my head against it for considerable time, I've only managed to set up CLion only as a glorified text editor, and nowhere near its capabilities that work out of the box on my own projects that I have complete control of and which are built natively. Is there some way to make it work for this project?
Update
I found out that my problems had nothing to do with working under a chroot, and everything to do with our build system being too much for CLion to handle. What I came up with is:
1) Forget that CLion can use CMake files natively. Build a compilation database using the build sytem.
2) ... run headfirst into a bug in CMake*. I managed to overcome it temporarily by manually modifying each cmake file containing a project.
3) Build the project, collect the .json files from the subdirectories (cmake still wouldn't generate them on Makefile generation, and they ended up in separate directories), write a script to glue them together into a single list.
4) Clear the source and build directories and re-download to undo all the kludges that I added while trying to get it to work.
5) Clear CLion caches, create a new project from the compilation database made in (3).
... and code navigation still doesn't work. No files from the 2.69 meg json are listed as project files. No symbols of any kind are found. I'm running out of ideas.
*) https://gitlab.kitware.com/cmake/cmake/issues/16588#note_248603
Update 2
It seems that statically generating a compilation database from our build system is a hopeless endeavour, since it generates new CMakeLists.txt that are in turn compiled by the makefile generated by the main CMakeLists.txt. I can't use clang with -MJ option, since clang is not present on the build environment, and I can't find a way to get clang to do a "dry run" on my host using the same files (even when -MJ is set, it still tries to compile normally). I can't use -DCMAKE_CXX_COMPILER and such options, because the build is designed for cross-compilation (using the same setup even when compiling for the host architecture) and doesn't actually use the system gcc/g++.
I made a script to create the compilation database from command line options:
````
#!/usr/bin/env python3
import os
import sys
import argparse
import json
commandline = sys.argv[1:]
compiler_args = sys.argv[2:]
parser = argparse.ArgumentParser(description='Generate a single line of compilation database from c(++) compiler command line.')
parser.add_argument('-o', dest='output', metavar='OUTPUT', action='store', type=str, help = "output file")
args = parser.parse_known_args(compiler_args)
sources = []
for arg in commandline:
if arg.endswith('.c') or arg.endswith('.cpp') or arg.endswith('.cc') or arg.endswith('.cxx'):
sources.append(arg)
output_file = args[0].output
if output_file:
entry = { 'directory': os.getcwd(), 'arguments': commandline, 'file': "", 'output': output_file }
for source in sources:
entry['file'] = source
json.dump(entry, sys.stdout)
sys.stdout.write('\n')
````
I use it during build by placing compiler wrappers in my PATH:
````
#!/usr/bin/env bash
if ! [ -z ${TRACE_CC_TEMP_FILE+x} ]; then
FILE=$TRACE_CC_TEMP_FILE
flock ${FILE} trace-cc-args.py /usr/bin/g++ "${@:1}" >> ${FILE} &
fi
exec /usr/bin/g++ "${@:1}"
````
Then I collect the results using another Python script:
````
#!/usr/bin/env python3
import sys
import json
list = []
for line in sys.stdin:
list.append(json.loads(line))
print(json.dumps(list, sort_keys=True, indent=2))
````
To set up the environment variables and collect the results:
````
#!/usr/bin/env bash
WORKSPACE_DIR=<my workspace>
BUILD_DIR=${WORKSPACE_DIR}/build
DB_FILE=${WORKSPACE_DIR}/compile_commands.json
TMP_FILE=$(mktemp)
export TRACE_CC_TEMP_FILE=${TMP_FILE}
#TMP_FILE=${TRACE_CC_TEMP_FILE}
rm ${TRACE_CC_TEMP_FILE}
touch ${TRACE_CC_TEMP_FILE}
cd ${WORKSPACE_DIR}
rm -rf ${BUILD_DIR}
mkdir ${BUILD_DIR}
cd ${BUILD_DIR}
cmake <source directory> <options>
time make "$@"
cd ${WORKSPACE_DIR}
if [ -f $DB_FILE ]; then
mv ${DB_FILE} ${DB_FILE}.old
fi
make-compilation-database.py < ${TMP_FILE} > ${DB_FILE}
````
warning: not recommended for your non-sandboxed environments
I then need to also replace the custom g++ and gcc:
````
>sudo mv /usr/bin/<custom-gcc> /usr/bin/raw-<custom-gcc>
>sudo ln -s /usr/bin/traced-<custom-gcc> /usr/bin/<custom-gcc>
````
where `traced-<custom-gcc>` scripts are like above:
````
#!/usr/bin/env bash
if ! [ -z ${TRACE_CC_TEMP_FILE+x} ]; then
FILE=$TRACE_CC_TEMP_FILE
flock ${FILE} trace-cc-args.py /usr/bin/gcc "${@:1}" >> ${FILE} &
fi
exec /usr/bin/raw-<custom-gcc> "${@:1}"
````
Since the <custom-gcc> isn't present on host where the compilation database will be read, I pretend that regular gcc was used.
Results
Clion still can't handle the project. The compilation database generated thus looks fine to me, and VS Code can properly load it (jump to definition/declaration is usable).
Update 3
I've confirmed that compile_commands.json generated with the scripts above (after fixing Python indentation) from a more normal build system works fine in CLion. VS Code, however, handles both. Perhaps there is some difference between how these two handle compiler paths.
请先登录再写评论。