Open sezaru opened 8 years ago
The headers issue is a bit more complicated than that: a header can be compiled differently in different compilation units and in my last project at work that happened. I wrote a bit about it in my blog. I'm not even sure what the ideal solution would be given the C and C++ compilation model.
The header support in cmake-ide right now was fine for me in a medium-sized mixed C and C++ codebase. What problems do you have?
I don't think I got what you mean, the only way I can see this happening is if the developer explicitly listed the same header in more than one output binary (add_executable or add_library), is that what you meant?
I've done a simple example of this, the CMakeLists.txt
would have something like this:
file (GLOB_RECURSE sources src/*.cpp)
file (GLOB_RECURSE sources2 src2/*.cpp)
file (GLOB_RECURSE headers include/*.hpp)
add_executable (TEST1 ${sources} ${headers})
target_include_directories(TEST1 PUBLIC ${CMAKE_SOURCE_DIR}/include ${OpenCV_INCLUDE_DIRS})
add_executable (TEST2 ${sources2} ${headers})
target_include_directories(TEST2 PUBLIC ${CMAKE_SOURCE_DIR}/include ${OPENSSL_INCLUDE_DIR})
Running my modified version of cmake will output this compile_commands.json
:
[
{
"directory": "/home/ebarreto/Downloads/cmake-3.6.1/test/build",
"command": "/usr/bin/c++ -I/home/ebarreto/Downloads/cmake-3.6.1/test/include -I/usr/include/openssl -o CMakeFiles/TEST2.dir/test.hpp.gch -x c++-header -c /home/ebarreto/Downloads/cmake-3.6.1/test/include/test.hpp",
"file": "/home/ebarreto/Downloads/cmake-3.6.1/test/include/test.hpp"
},
{
"directory": "/home/ebarreto/Downloads/cmake-3.6.1/test/build",
"command": "/usr/bin/c++ -I/home/ebarreto/Downloads/cmake-3.6.1/test/include -I/usr/include/openssl -o CMakeFiles/TEST2.dir/src2/test2.cpp.o -c /home/ebarreto/Downloads/cmake-3.6.1/test/src2/test2.cpp",
"file": "/home/ebarreto/Downloads/cmake-3.6.1/test/src2/test2.cpp"
},
{
"directory": "/home/ebarreto/Downloads/cmake-3.6.1/test/build",
"command": "/usr/bin/c++ -I/home/ebarreto/Downloads/cmake-3.6.1/test/include -I/usr/include/openssl -o CMakeFiles/TEST2.dir/src2/main.cpp.o -c /home/ebarreto/Downloads/cmake-3.6.1/test/src2/main.cpp",
"file": "/home/ebarreto/Downloads/cmake-3.6.1/test/src2/main.cpp"
},
{
"directory": "/home/ebarreto/Downloads/cmake-3.6.1/test/build",
"command": "/usr/bin/c++ -I/home/ebarreto/Downloads/cmake-3.6.1/test/include -I/usr/include/opencv -o CMakeFiles/TEST1.dir/test.hpp.gch -x c++-header -c /home/ebarreto/Downloads/cmake-3.6.1/test/include/test.hpp",
"file": "/home/ebarreto/Downloads/cmake-3.6.1/test/include/test.hpp"
},
{
"directory": "/home/ebarreto/Downloads/cmake-3.6.1/test/build",
"command": "/usr/bin/c++ -I/home/ebarreto/Downloads/cmake-3.6.1/test/include -I/usr/include/opencv -o CMakeFiles/TEST1.dir/src/test1.cpp.o -c /home/ebarreto/Downloads/cmake-3.6.1/test/src/test1.cpp",
"file": "/home/ebarreto/Downloads/cmake-3.6.1/test/src/test1.cpp"
},
{
"directory": "/home/ebarreto/Downloads/cmake-3.6.1/test/build",
"command": "/usr/bin/c++ -I/home/ebarreto/Downloads/cmake-3.6.1/test/include -I/usr/include/opencv -o CMakeFiles/TEST1.dir/src/main.cpp.o -c /home/ebarreto/Downloads/cmake-3.6.1/test/src/main.cpp",
"file": "/home/ebarreto/Downloads/cmake-3.6.1/test/src/main.cpp"
}
]
The important parts are the duplication of test.hpp, in one case it has a include path to openssl, in the other it is one to opencv, since this header should work with both the cases, the logical thing to do here is merge both parts into one and remove any flag that are specific to one of the parts, so -I/home/ebarreto/Downloads/cmake-3.6.1/test/include
will remain, but -I/usr/include/opencv
and -I/usr/include/openssl
will be removed, resulting exactly in the right compiler flags for the header file test.hpp.
Is that the case you mentioned? If not, can you elaborate more about it so I can reproduce it here?
Thanks
No, I mean that foo.cpp
and bar.cpp
could both include hdr.hpp
and that each one of those source files can be compiled with different flags, with hdr.hpp
not appearing anywhere in the CMakeLists.txt
explicitly. Which flags should be used when a user visits hdr.hpp
?
You can only workaround this if you apply a post-processing, wrapping the make command or using the compile_commands.json
to parse all cpp files searching for includes.
I've made the second option using libclang, it parses all the cpp files from the project searching for #include
directives, it will then apply the logic I talked in the above post to find out the correct flags for the header file. It works like a charm, but I don't like it since it is another step needed instead of simply using cmake.
Note that my proposal is about explicitly adding the headers files to the project CMakeLists.txt's files, if the user does that, the problem you talked about simply disappear.
My proposal is very similar to what Qt-Creator IDE does, when opening a cmake project with Qt-Creator, Qt-Creator will generate a cbp file from cmake and use it to find what are the project files and compiler flags, if you explicitly add your headers to the CMakeLists.txt file, Qt-Creator will list it in the project panel and will find the correct flags for it.
I know that not everyone adds it's header files to the CMakeLists.txt file, but in this case, you can just fallback to the current cmake-ide mode to find the flags or even use the libclang solution I talked about.
cmake-ide
is already trying to find source files that include the header in question to apply flags. The only problem is it can be slow in large projects. But the functionality is already there.
As far as I know, what cmake-ide
does is simply try to compile the header file with one of the provided compiler flags from the cpp files from compile_commands.json
. That doesn't work with the example I gave before..
For example cmake-ide
gave to test.hpp these flags:
"-I/home/ebarreto/Downloads/cmake-3.6.1/test/include" "-I/usr/include/openssl" "-o" "CMakeFiles/TEST2.dir/src2/test2.cpp.o"
But the correct should be only:
"-I/home/ebarreto/Downloads/cmake-3.6.1/test/include"
These differences would make flycheck
not recognize as an error every time I include or use something for openssl
for example.
It tries a bunch of things, some of which are configurable and off by default due to speed reasons
Hello there,
cmake-ide uses the
compile_commands.json
file to grab the project files compiler flags, but since this file doesn't show any information about the compiler flags of header files, we need to try finding it with some hacky way (like find a source file with the same name and using it's compiler flags), this works in simple projects, but in anything more complex, problems will arise.I've made some simple changes to the cmake's project source code so it will insert header information in the
compile_commands.json
file too, (you obviously need to list the headers files in theCMakeLists.txt
file, for exampleadd_executable(project main.cpp test.cpp test.hpp)
), but it doesn't seems like it will be accepted mainstream (you can see my bug report here bug report link maybe you can help me convince the cmake devs that there is people interested in this feature.Regardless of that, one already built-in solution in cmake is to use the CodeBlocks generator file instead of the
compile_commands.json
since that one will show all the information about every file you listed in yourCMakeLists.txt
file, including headers.The problem is that this format is not as straight forward as the
compile_command.json
since it needs a little bit more logic to grab all the compiler flags information. But since this will give all the information we need without relying in hacks and always work despite the project size or complexity, maybe is a great alternative to make emacs works better as a real IDE.