Add include directories to AUTOMOC - c++

I have a ROS package that includes QT4 GUIs. My code is in the folder
Project_name/src/test/*.cpp
and my includes in
Project_name/include/test/*.h
Some qt4 mocs must be created as some header files contain Q_OBJECT in their classes.
I tried the
set(CMAKE_AUTOMOC ON)
in the cmake file but as it seems it does not search the /include/test/ folder. AUTOMOC states that works either bu searching the source files for moc_**.cpp files or by examining the header files for Q_OBJECT.
I also tried to include a moc_***.cpp in a source file (for example /src/test/a.cpp). So it searched for a.h but could not find it in include/test/a.h.
I must note that if I remove the Q_OBJECT from the classes the compilation succeeds, as the include/ folder is added like this:
include_directories( include
${catkin_INCLUDE_DIRS}
)
Finally I've tried to use QT4_WRAP_CPP but for some reason it couldn't find the mocs as well and the link failed (although in another project with the same parameters in the cmake file works :/)
Edit :
Found a solution. In added in the cpp file:
#include "../../include/test/moc_a.cpp"
and found the .h in include/test.
Though something tells me that it is not the correct way :P

#include "../../include/test/moc_a.cpp" in cpp file works but not well for libraries that may be built sometimes as static libraries within bigger project and sometimes by themselves. The problem is that include directory can be created in a not-suitable location, which pollutes code, causes problems with VCS.
qt_wrap_cpp works best for me. It supports both qt4 and qt5, does not require including moc in cpp file. The syntax:
include_directories(${CMAKE_CURRENT_BINARY_DIR}) # including binary dir is
# necessary only if there are classes with Q_OBJECT macro declared in cpp
# files (these cpp files should also contain `# include "x.moc"` at the end).
set(CMAKE_AUTOMOC ON)
include_directories(${Include_Directories})
set(Sources ${Sources_Path}/a.cpp ${Sources_Path}/b.cpp
... ${Sources_Path_z}/z.cpp)
qt_wrap_cpp(${Target_Name} Sources ${Headers_Path}/header1.hpp
${Headers_Path_2}/header2.hpp ... ${Headers_Path_N}/headerN.hpp)
add_library(${Target_Name} STATIC ${Sources})
# OR add_executable(${Target_Name} ${Sources})
Naturally, only headers that contain Q_OBJECT macro and are not in the same directory as corresponding sources must be passed to qt_wrap_cpp.

Related

CMake: Can we specify include directories for a specific set of files not forming an executable or lib?

If I have this source tree:
C:\app:
src:
CMakeLists.txt
main.cpp --> #include "acme/header_only_lib/api.h"
D:\3rdparty\acme\header_only_lib:
api.h --> #include "detail.h"
detail.h
Without using symlink tricks, and without adding files to the 3rdparty folders, if I must retain #include "acme/header_only_lib/api.h" in main.cpp, how should I specify the include directories in CMake such that api.h can see detail.h, without adding global include directory of D:\3rdparty\acme\header_only_lib? The header-only-lib is not an executable nor library target, and its code is not modifiable by me. I also don't want to pollute my global include directories by adding D:\3rdparty\acme\header_only_lib because the filenames inside there are too common and will easily clash with other libraries/future code.
Is there a CMake mechanism where I can say:
Only for D:\3rdparty\acme\header_only_lib\api.h, add D:\3rdparty\acme\header_only_lib as the include directory?
To add a directory to the global list of include directories, you use e.g.
include_directories( ${CMAKE_SOURCE_DIR}/3rdparty )
Note that you should not hardcode absolute paths (like D:\) into your CMakeLists.txt as that makes it impossible to build your project in any other location. CMake offers variables like ${CMAKE_SOURCE_DIR} and ${CMAKE_BINARY_DIR} for just that purpose.
If you want to add a directory to the list of include directories for a specific part of your build only, you use e.g.
target_include_directories( app PRIVATE ${CMAKE_SOURCE_DIR}/3rdparty )
This adds the directory only for the target (executable / library) app.
Note that, if your acme/header_only_lib is supposed to be installed alongside with the app binaries, this approach won't work, as your acme headers would need to "see" each other on the client's machine, which is unlikely if they reside in the acme/header_only_lib subdirectory but address each other without subdirs. That would require your client (who isn't using your CMakeLists.txt for his builds) to add acme/header_only_lib to the include paths for your header lib to work -- you should not do that.
Use include_directories or target_include_directories:
include_directories("D:\3rdparty")
OR with target_include_directories if you want to make this change only for the main target:
add_executable(main main.cpp)
target_include_directories(main PUBLIC "D:\3rdparty")
Then you can just #include "acme/header_only_lib/api.h" or #include <acme/header_only_lib/api.h>
Header only lib
If you want to do this for header-only-lib only, you need to do this in it's CMake file. First add the library as INTERFACE with no source files:
add_library(header-only INTERFACE)
Then include directories for it:
target_include_directories(header-only INTERFACE include-dir-for-header-only)
Then link it to the main target
find_library(HeaderOnly
NAMES header-only
HINTS "D:\3rdparty\path-to-lib"
)
target_link_libraries(main header-only)

In CLion, header only library: file "does not belong to any project target, code insight features might not work properly"

I have a header-only library project set up with the cmake command:
add_library(my_library INTERFACE)
and I also added
target_sources(my_library INTERFACE ${MY_LIRBARY_HEADER_FILES})
but when I open a source file, I get the warning:
This file does not belong to any project target, code insight features might not work properly
and I lose a lot of the functionality on things like code completion.
What is the proper way to set this up so CLion provides its usual functionality on a header-only library?
Little background
I was having the same problem, albeit the project was not header-only, nevertheless, the open files from inc folder were throwing the aforementioned warning, even though the CMake file clearly marked that folder to be include_directory.
*.hpp files do not belong to ${SOURCE}
include_directories("${PROJECT_SOURCE_DIR}/inc/")
add_subdirectory(src)
add_executable(${EXECUTABLE_NAME} main.cpp ${SOURCE})
Since this is a perfectly valid CMake file and adding the include files to source files is not idiomatic, I did not want to amend the CMake file.
The solution
As described on the official JetBrains Forum, the CMake file is indeed valid and the warning is shown because of the inability of CLion to properly index header files. The suggested workaround extracted from the link is to right-click the folder and Mark directory as | Library Files/Project Sources and Headers.
So, this header isn't includes in executables and CLion notifies you that some code insight features might not work properly. As workaround you can use "Mark directory as" Library Files/Project Source and Headers for folder.
Clion takes information about source files from CMake build system. When you add any cpp file to sources list CMake automatically tell about header with same name. So if cpp/h names differs (or you don't have cpp file at all) you should include header manually.
set(Sources my_lib.cpp)
set(Headers header_of_my_lib.h)
add_executable(superlib ${Sources} ${Headers})
If you don't have any executable you can omit last line, CLion will still know about files
This warning is an IDE issue that Android Studio cannot recognise the current directory if it does not include any source files.
Workaround
Adding am empty source file, e.g empty_xxx.c under the directory in question and adding below line in your corresponding CMakeList.txt
add_library(${TARGET_NAME_XXX} SHARED ${SOME_DIR_HAVING_THIS_WARNING}/empty_xxx.c)
will help get rid of this warning.
You can add the header files to your project like this:
set(SOURCE_FILES main.cpp MyClass1.cpp MyClass1.h MyClass2.cpp MyClass2.h)
You can also set it in multiple steps like so:
set(SOURCE_FILES main.cpp)
set(SOURCE_FILES ${SOURCE_FILES} MyClass1.cpp MyClass1.h)
set(SOURCE_FILES ${SOURCE_FILES} MyClass2.cpp MyClass2.h)
Though as mentioned in the comments, you probably shouldn't be adding the header files to your project at all.

Preventing CMake-generated makefile for optional-header-only library from compiling source files in header-only mode

I have a library that can both be used as an header-only library and as a traditional library. To enable this optional-header-only functionality, the library includes .cpp source files if compiled in header-only mode. Example:
// Vector.hpp
// (Module file), intended to be included manually by the user
#ifndef LIBRARY_MODULE_VECTOR
#define LIBRARY_MODULE_VECTOR
#include "Library/Vector/Inc/Vector2.hpp"
#include "Library/Vector/Inc/Vector3.hpp"
#include "Library/Vector/Inc/VectorUtils.hpp"
#if defined(LIBRARY_HEADERONLY)
#include "Library/Vector/Src/Vector2.cpp"
#include "Library/Vector/Src/Vector3.cpp"
#include "Library/Vector/Src/VectorUtils.cpp"
#endif
#endif
When the user includes Vector.hpp in one of his/her projects, if LIBRARY_HEADERONLY is defined, the implementation source files will be included right after the header files. Careful usage of the inline keyword is applied to avoid multiple definitions.
If LIBRARY_HEADERONLY is undefined, the .cpp files will be compiled and the library will have to be linked.
My build system of choice is CMake.
Using a CMake flag, the user can define or undefine LIBRARY_HEADERONLY.
The CMakeLists.txt file is similar to this:
# (not shown) set flag and cache variables...
# Include library directory
include_directories("./${INCLUDE_DIRECTORY}")
# Glob all library header/source files
file(GLOB_RECURSE SRC_LIST "${INC_DIR}/*" "${SRC_DIR}/*")
# (Not shown) Check if header-only mode is enabled
# (from now on we assume header-only mode is enabled and that
# LIBRARY_HEADERONLY is defined)
# Use all source/header files as a library target
add_library(HEADER_ONLY_TARGET STATIC ${SRC_LIST})
set_target_properties(HEADER_ONLY_TARGET PROPERTIES LINKER_LANGUAGE CXX)
install(DIRECTORY ${INC_DIR} DESTINATION .)
Unfortunately, the CMake-generated makefile always compiles the .cpp files, even when header-only mode is enabled and the target is HEADER_ONLY_TARGET.
How can I prevent the CMake-generated makefile from compiling the source files in header-only mode?
Note that IDEs reliant on CMake-generated output, such as Qt Creator, should display both the header and source files as part of the project.
If I don't glob any source file, but only the .hpp header files, CMake will complain that no source files were selected for a library target, and IDEs that rely on CMake files will not display any item.
Try setting the source files' HEADER_FILE_ONLY property to prevent them from building, e.g.:
if (LIBRARY_HEADERONLY)
set_source_files_properties(${SRC_LIST} PROPERTIES HEADER_FILE_ONLY 1)
...
endif()
Also see the documentation.
if (Create_Header_Only)
add_library(TargetName INTERFACE)
# Clients will build with -DLIBRARY_HEADERONLY
target_compile_definitions(TargetName INTERFACE LIBRARY_HEADERONLY)
else()
add_library(TargetName STATIC thesource.cpp)
endif()
# Clients will build with -Iinclude
target_include_directories(TargetName INTERFACE include)
Client code just does:
add_executable(mine main.cpp)
target_link_libraries(mine TargetName)
See also Transitive Usage Requirements and all the rest of those CMake manuals regarding creating packages, etc.
An approach of defining all library types and letting the consumer choose between them is outlined in:
Opt-in header-only libraries with CMake
Something like:
add_library(lib_shared SHARED ...)
add_library(lib_shared STATIC ...)
add_library(lib_iface INTERFACE)
So that the consumer makes the choice of which to link to:
# target_link_libraries(consumer lib_static)
# target_link_libraries(consumer lib_shared)
target_link_libraries(consumer lib_iface)
Why do you not separate the GLOB for HEADERS and SRC files? You could add a dummy.cpp (a empty .cpp file) for creating header-only libraries. I mean:
# Glob all library header files
file(GLOB_RECURSE HEADER_ONLY_LIST "${INC_DIR}/*.hpp")
# Glob all library src files
file(GLOB_RECURSE SRC_ONLY_LIST "${SRC_DIR}/*.cpp")
# Check if LIBRARY_HEADERONLY is defined, so you can filter the target files
if(LIBRARY_HEADERONLY)
set(SRC_LIST ${HEADER_ONLY_LIST} dummy.cpp) # I don't know if it's needed to add a dummy.cpp file with your set_target_properties(HEADER_ONLY_TARGET ...)
else()
set(SRC_LIST ${HEADER_ONLY_LIST} ${SRC_ONLY_LIST})
endif(LIBRARY_HEADERONLY)
# Use all source/header files as a library target
add_library(HEADER_ONLY_TARGET STATIC ${SRC_LIST})
set_target_properties(HEADER_ONLY_TARGET PROPERTIES LINKER_LANGUAGE CXX)
install(DIRECTORY ${INC_DIR} DESTINATION .)
Anyway, CMake 3.X.X gives you the chance for creating INTERFACE libraries (header-only ones).

CMake - Weird Include Directories

I have created a project which consists of a main.cpp file and another class (named Physical) that is broken up into a Physical.hpp file and Physical.cpp file.
The project file structure looks like this:
main.cpp
header/Physical.hpp
src/Physical.cpp
The project compiles fine, but only if I include Physical.hpp in different ways depending on whether or not I'm including from the Physical.cpp or main.cpp file.
From the main file, I have to use:
#include "header/Physical.hpp"
Whereas, from the Physical.cpp file I have to use:
#include "../header/Physical.hpp"
Why is there this discrepancy? I expect it has something to do with my cmake configuration file, although I'm really not sure. Below is my cmake config file.
cmake_minimum_required(VERSION 2.8.4)
project(gravity_simulator ${PROJECT_BINARY_DIR})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES main.cpp src/Physical.cpp)
include_directories("${PROJECT_BINARY_DIR}")
add_executable(gravity_simulator ${SOURCE_FILES})
# Detect and add SFML
set(CMAKE_MODULE_PATH "/usr/share/SFML/cmake/Modules/" ${CMAKE_MODULE_PATH})
#Find any version 2.X of SFML
#See the FindSFML.cmake file for additional details and instructions
find_package(SFML 2 REQUIRED system window graphics network audio)
if(SFML_FOUND)
include_directories(${SFML_INCLUDE_DIR})
target_link_libraries(gravity_simulator ${SFML_LIBRARIES})
endif()
Everything works as expected.
For your main.cpp file the header is located at header/Physical.hpp while for your Physical.cpp the header is located at ../header/Physical.hpp.
The mistake here is, that you think the relative path would always start from a specific directly, while instead every source file (*.cpp) gets compiled independently and thus the header search is happening for each file independently.
Personally if I don't write a library, I simply put all my source and header files in a src directory and everything will be fine. However if I'm writing a library, I use the <header.hpp> style and add the header directory to the include directory (include_directories("header")). The whole reason why one usually splits up things into header and source files is, so when one ships a library one can easily just ship the headers and doesn't have manually filter them out between the source files.
tl;dr When writing an application put everything a source directory. When writing a library, use the <> for the inclusion add the header directory to the include directories.

Using cmake's automoc on external header files without knowing their filenames

In essence I want to be able to moc header files that are not part of any target in cmake with the additional difficulty that I don't know the filenames of those headers.
The actual project is quite complex and part of an automated build system. The following is an easy example.
Consider a project structured like this:
CMakeLists.txt
src/lib/source.cpp
src/lib/CMakeLists.txt
src/include/some_header.hpp # which is included in source.cpp
Content of main CMakeLists.txt:
cmake_mimimum_required(VERSION 2.8.6)
project("automoctest")
add_subdirectory(src/lib)
Content of src/lib/CMakeLists.txt:
include_directories(${CMAKE_HOME_DIRECTORY}/src/include)
find_package(Qt4 4.8 REQUIRED QtCore)
include(UseQt4)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_library(foo SHARED source.cpp)
target_link_libraries(foo ${QT_LIBRARIES})
set_target_properties(foo PROPERTIES AUTOMOC true)
Inside source.cpp the file some_header.hpp is included like this:
#include "some_header.hpp"
The Problem:
The file some_header.hpp includes a Q_OBJECT and has some signals, so moc needs to work its magic. But as the header is not inside the actual project the header will not get mocked. I don't even know the filename of some_header.hpp so I can't add it specifically to be mocked. Obviously AUTOMOC does not check the include_directories for mockable files even when a source file includes one of them.
What I tried (unsuccessfully):
use #include moc_some_header.cpp in source.cpp as it is described in the cmake documentation. This leads to an error in which cmake complains that it could not find some_header{.h,.hpp,.hxx,.H}
setting CMAKE_AUTOMOC_RELAXED_MODE to true. Even though it's not clear from the doc what this actually does. Made no difference anyway.
setting AUTOMOC_MOC_OPTIONS to -Isrc/include or -I/path/to/project/src/include or -I${CMAKE_HOME_DIRECTORY}/src/include Doesn't do anything that I could see.
The great thing about AUTOMOC is that I don't need to know which files actually need to be mocked. In this case however I would need to know all the headers that might have a Q_OBJECT inside, that are included by my source files.
Is there a way to tell AUTOMOC where exactly to look for mockable files?
Did you truly set AUTOMOC_MOC_OPTIONS to -Isrc/include, or to -I/path/to/myproject/src/include? The former probably doesn't exist.
I have always used the MOC macros; it looks like AUTOMOC is something new that is built into CMake.
I usually include all headers when creating a library or executable - i.e.
add_library(foo SHARED source.cpp ../include/some_header.hpp )
I assume that this will allow AUTOMOC to work. It will have the added benefit of causing make to work as expected - rebuilding your library when the header changes.
If you are truly unable to add the file to the add_library command ahead of time, then I think you'll have to write a cmake function to search for #include statements within source.cpp, locate those files, and search them for Q_OBJECT. If they match, add them to a variable - perhaps EXTRA_MOCS. Then, the add_library line becomes
add_library(foo SHARED source.cpp ${EXTRA_MOCS} )