Hi
I’m try to create a root dictionary with a CMake target. Most of the time, my data structures are only defined in header files without any source files. Therefore, the CMake target that includes those header files aren’t a really library or executable:
add_library(MyDataStructs INTERFACE)
target_include_directories(MyDataStructs INTERFACE ${CMAKE_CRRUENT_SOURCE_DIR})
target_link_libraries(MyDataStructs INTERFACE ROOT::RIO)
ROOT_GENERATE_DICTIONARY(myData_dict MyData1.hpp MyData2.hpp MODULE MyDataStructs LINKDEF DataLinkDef.h)
This doesn’t work giving an error:
Cannot find header MyData1.hpp to generate dictionary myData_dict for. Did
you forget to set the INCLUDE_DIRECTORIES property for the current
directory?
Call Stack (most recent call first):
data/CMakeLists.txt:6 (ROOT_GENERATE_DICTIONARY)
So how do I generate root dictionary with a header-only cmake target?
ROOT Version: 6.30.02
Platform: Debian Buster
Compiler: gcc 13
Can you provide a simple example reproducing the issue? The error message is just telling it doesn’t find the header file:
Cannot find header MyData1.hpp to generate dictionary myData_dict for. Did
you forget to set the INCLUDE_DIRECTORIES property for the current
directory?
Hi, @bellenot
Thanks very much for your reply. Yes, I have a simple example. Please check this github repo. In the repo, I put the data structure in /data/
folder with the corresponding CMakeLists.txt.
So I got the cmake errors as is shown above. But if I change it to a shared library (by defining a constructor in a source file), then everything could works out. But then I have to define that unnecessary constructor in the source file.
OK, thanks I’ll try to test it maybe tomorrow. In the meanwhile, did you see Root_generate_dictionary ? It has a header only dictionary…
So I just tried, and this works (on Windows, but it shouldn’t matter):
I copied the data/MyData.hpp
and data/DataLinkDef.h
files in the parent directory, then using this CMakeLists.txt
:
cmake_minimum_required(VERSION 3.27)
project(test_root)
find_package(ROOT REQUIRED)
include(${ROOT_USE_FILE})
link_directories(${ROOT_LIBRARY_DIR})
include_directories(${ROOT_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR})
add_executable(write_data write.cpp)
target_link_libraries(write_data PRIVATE ROOT::RIO ROOT::Tree)
set_property(TARGET write_data PROPERTY ENABLE_EXPORTS 1)
if(MSVC)
set_target_properties(write_data PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
endif()
add_executable(read_data read.cpp)
target_link_libraries(read_data PRIVATE ROOT::RIO ROOT::Tree)
set_property(TARGET read_data PROPERTY ENABLE_EXPORTS 1)
if(MSVC)
set_target_properties(read_data PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
endif()
ROOT_GENERATE_DICTIONARY(readData_dict MyData.hpp MODULE read_data LINKDEF DataLinkDef.h)
ROOT_GENERATE_DICTIONARY(writeData_dict MyData.hpp MODULE write_data LINKDEF DataLinkDef.h)
And it seems to work:
C:\Users\bellenot\rootdev\Forum\EdwinYZ\root_forum_1\build\Release>write_data.exe
C:\Users\bellenot\rootdev\Forum\EdwinYZ\root_forum_1\build\Release>read_data.exe
0
my data
1
my data
2
my data
3
[...]
my data
998
my data
999
my data
C:\Users\bellenot\rootdev\Forum\EdwinYZ\root_forum_1\build\Release>
(note that generating one dictionary per target is maybe not needed…)
Thanks for trying out.
But in your example
ROOT_GENERATE_DICTIONARY(readData_dict MyData.hpp MODULE read_data LINKDEF DataLinkDef.h)
read_data
target is NOT a header-only target. Sometimes a project only contains header files without any executable. I won’t whether it’s still possible to generate a dictionary in this case.
As I said, the dictionary is generated with only the header file (there is no source file) and it works. Now, if it’s not what you’re asking for, I might have misunderstood your question…
Sorry for the misunderstanding.
The issue that I’m trying to point here is about header-only targets, instead of only header files. I hope we both agree that these two are very different things. 
A cmake target could represent a library, an executable or a group of header files without any source files. We could generate root dictionary by giving the target name as the MODULE
argument, as is for read_data
in
ROOT_GENERATE_DICTIONARY(readData_dict MyData.hpp MODULE read_data LINKDEF DataLinkDef.h)
However, the issue here is that if the target has no source files (either only containing header files or possessing an include dir), the ROOT_GENERATE_DICTIONARY
seems not to work anymore.
Hope I could make it clearer.
Cheers
Oh, OK, thanks! So if I understand correctly, it is not a CMake issue, but a dictionary generation issue instead, right? Not even with rootcling in the terminal?
Thanks for this tip. Yes, I tried with rootcling and it does work with only header files. But I also found that rootcling also generates a source file for the dictionary, which could be the reason why header-only target can’t work at all.
Therefore I found the solution with this info. Instead of declaring the target with INTERFACE
:
add_library(myData INTERFACE)
target_include_directories(myData PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(myData PRIVATE ROOT::RIO)
declare the target with either SHARED
or STATIC
:
add_library(myData SHARED)
target_include_directories(myData PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(myData PRIVATE ROOT::RIO)
Then it works as expected.
Can you try with something like this:
ROOT_GENERATE_DICTIONARY(readData_dict MyData.hpp LINKDEF DataLinkDef.h)
I.e. without MODULE
?
Yes, but then I have to manually deal with include path for those headers. 
But thanks for the info.
You’re welcome. And right, the dictionary generation generates source file(s)…