List all subprojects in doxygen main page - cmake

I want to have my doxygen main page to list all my sub projects and refer to their respective README.md file.
In every subproject's CMakeLists.txt (each project is in its own subfolder) I call the function REGISTER_TARGET(my_project_name) which is defined as
macro(REGISTER_TARGET TARGET)
# Storing target name and directory as 2D-array
SET(GLOBAL_TARGETS "${GLOBAL_TARGETS};${TARGET}\;${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "source_list")
# doing other things concerning the build
...
endmacro(REGISTER_TARGET)
And in my doxygen's CMakeLists.txt I do
SET(DOXYGEN_GLOBAL_TARGETS "")
foreach(pair ${GLOBAL_TARGETS})
LIST(GET pair 0 local_project_name)
LIST(GET pair 1 local_project_dir)
SET(local_project_readme "${local_project_dir}/README.md")
LIST(APPEND DOXYGEN_FILES ${local_project_readme})
SET(DOXYGEN_GLOBAL_TARGETS "${DOXYGEN_GLOBAL_TARGETS}\n- ${local_project_name}. #ref ${local_project_readme}")
endforeach()
...
CONFIGURE_FILE("${DOXYGEN_MAINFILE_IN}" "${DOXYGEN_MAINFILE}" #ONLY)
And my DOXYGEN_MAINFILE_IN looks like
This is the main page
======
Sub projects
------------
#DOXYGEN_GLOBAL_TARGETS#
This turns out in DOXYGEN_MAINFILE as:
This is the main page
======
Sub projects
------------
- name_of_project1. #ref C:/very/ugly/source/path/name_of_project1/README.md
- name_of_project2. #ref C:/very/ugly/source/path/name_of_project2/README.md
which does not correctly link to this file (in HTML, the whole path is shown and the last path is rendered as hyperlink but refers to an empty file). The HTML for one entry looks similar to
<li>name_of_project1. C:/very/ugly/<a class="el" href="da/ddd/README_8md.html">source/path/name_of_project1/README.md</a></li>
So
a) how can I turn the absolute path to a markdown file in my to a working #ref target (which also displays the first header as link text). Keep in mind, that the above file paths are source-directory so the doc files will reside in a completely different place.
OR
b) which information do i have to serialize in my REGISTER_TARGET CMake macro which can then be turned in such a hyperlink.
I know that it is theoretically possible (OpenCV does it in a quite similar way but I failed to reproduce it)

Related

Why doesn't cmake find_package(VTK) find VTK_INCLUDE_DIRS after building VTK from source and installing?

I’m running cmake version 3.23.0-rc1, on ubuntu 20.04.
I built vtk-8.2 from source; cmake, make, then ‘make install’. Now I am trying to find the VTK package for my own application, using cmake’s find_package(VTK). The application’s CMakeLists.txt contains this:
find_package(VTK)
message("VTK_FOUND: ${VTK_FOUND}")
message("VTK_INCLUDE_DIRS: ${VTK_INCLUDE_DIRS}")
message("VTK_LIBRARIES: ${VTK_LIBRARIES}")
Result is that VTK_FOUND=1, VTK_LIBRARIES contains many entries, but VTK_INCLUDE_DIRS is blank/empty. Why would this be?
I do see file /usr/local/lib/cmake/vtk-8.2, which contains many *.cmake files. But I don’t see a corresponding /usr/local/include/cmake directory, despite the presence of /usr/local/include/vtk-8.2. Is that expected? Here is the output:
VTK_FOUND: 1
VTK_INCLUDE_DIRS:
VTK_LIBRARIES: VTK::WrappingTools;VTK::ViewsQt;VTK::ViewsInfovis;VTK::CommonColor;VTK::ViewsContext2D;VTK::loguru;VTK::TestingRendering;VTK::TestingCore;VTK::vtksys;VTK::RenderingQt;VTK::PythonContext2D;VTK::RenderingVolumeOpenGL2;VTK::RenderingOpenGL2;VTK::glew;VTK::opengl;VTK::PythonInterpreter;VTK::Python;VTK::RenderingLabel;VTK::octree;VTK::RenderingLOD;VTK::RenderingImage;VTK::RenderingContextOpenGL2;VTK::IOVeraOut;VTK::hdf5;VTK::IOTecplotTable;VTK::IOSegY;VTK::IOParallelXML;VTK::IOPLY;VTK::IOOggTheora;VTK::theora;VTK::ogg;VTK::IONetCDF;VTK::netcdf;VTK::IOMotionFX;VTK::pegtl;VTK::IOParallel;VTK::jsoncpp;VTK::IOMINC;VTK::IOLSDyna;VTK::IOInfovis;VTK::libxml2;VTK::zlib;VTK::IOImport;VTK::IOGeometry;VTK::IOVideo;VTK::IOMovie;VTK::IOExportPDF;VTK::libharu;VTK::IOExportGL2PS;VTK::RenderingGL2PSOpenGL2;VTK::gl2ps;VTK::png;VTK::IOExport;VTK::RenderingVtkJS;VTK::RenderingSceneGraph;VTK::IOExodus;VTK::exodusII;VTK::IOEnSight;VTK::IOCityGML;VTK::pugixml;VTK::IOAsynchronous;VTK::IOAMR;VTK::InteractionImage;VTK::ImagingStencil;VTK::ImagingStatistics;VTK::ImagingMorphological;VTK::ImagingMath;VTK::GUISupportQtSQL;VTK::IOSQL;VTK::sqlite;VTK::GUISupportQt;VTK::GeovisCore;VTK::libproj;VTK::InfovisLayout;VTK::ViewsCore;VTK::InteractionWidgets;VTK::RenderingVolume;VTK::RenderingAnnotation;VTK::ImagingHybrid;VTK::ImagingColor;VTK::InteractionStyle;VTK::FiltersTopology;VTK::FiltersSelection;VTK::FiltersSMP;VTK::FiltersPython;VTK::FiltersProgrammable;VTK::FiltersPoints;VTK::FiltersVerdict;VTK::verdict;VTK::FiltersParallelImaging;VTK::FiltersImaging;VTK::ImagingGeneral;VTK::FiltersHyperTree;VTK::FiltersGeneric;VTK::FiltersFlowPaths;VTK::FiltersAMR;VTK::FiltersParallel;VTK::FiltersTexture;VTK::FiltersModeling;VTK::FiltersHybrid;VTK::RenderingUI;VTK::DomainsChemistry;VTK::CommonPython;VTK::WrappingPythonCore;VTK::ChartsCore;VTK::InfovisCore;VTK::FiltersExtraction;VTK::ParallelDIY;VTK::diy2;VTK::IOXML;VTK::IOXMLParser;VTK::expat;VTK::ParallelCore;VTK::IOLegacy;VTK::IOCore;VTK::doubleconversion;VTK::lz4;VTK::lzma;VTK::utf8;VTK::FiltersStatistics;VTK::eigen;VTK::ImagingFourier;VTK::ImagingSources;VTK::IOImage;VTK::DICOMParser;VTK::jpeg;VTK::metaio;VTK::tiff;VTK::RenderingContext2D;VTK::RenderingFreeType;VTK::freetype;VTK::kwiml;VTK::RenderingCore;VTK::FiltersSources;VTK::ImagingCore;VTK::FiltersGeometry;VTK::FiltersGeneral;VTK::CommonComputationalGeometry;VTK::FiltersCore;VTK::CommonExecutionModel;VTK::CommonDataModel;VTK::CommonSystem;VTK::CommonMisc;VTK::CommonTransforms;VTK::CommonMath;VTK::CommonCore
find_package(VTK) no longer sets VTK_INCLUDE_DIRS variable. If you look into description part of vtk-config.cmake (script CMake/vtk-config.cmake.in contains template of that file), then you find no note about VTK_INCLUDE_DIRS.
Since VTK_LIBRARIES variable contains IMPORTED targets (in form of VTK::foo), linking with the content of that variable using target_link_libraries will automatically provide include directories.

CMake rule to copy one of multiple identically-named files

Let's say we have a project like this:
foo
+-bar
+ +-header.h <-- copy if updated
+-baz
+ +-header.h <-- copy if updated
+-wibble
+ +-ni
+ +-header.h <-- copy if updated
target
+-header.h <-- to here
We have three possible candidates for header.h, but one final location; we're not using symbolic links for reasons. Note that there are actually around 350 header files with just a few duplicates, so listing each individually is troublesome, especially if these subdirectories update their header files. Currently, we do this unconditional copy:
file(glob_recurse HEADERS foo/*.h)
file(COPY ${HEADERS} DESTINATION target)
However, this rule only runs when we do a CMake rebuild and not when only header files change, so I would like to get this working for header file changes alone.
Now, looking at this answer I try something like this:
file(glob_recurse HEADERS foo/*.h)
foreach(file_i ${HEADERS})
get_filename_component(barename, ${file_i} NAME)
add_custom_command(
OUTPUT target/${barename}
COMMAND ${CMAKE_COMMAND}
ARGS -E copy ${file_i} target
)
endforeach( file_i )
However, CMake complains with the error:
CMake Error: Attempt to add a custom rule to output "target/header.h" which already has a custom rule.
I understand why I get the error, but I cannot think of any way to do what I want to do.

cmake - preset settings for entries from ini file

I have a project that uses some third party libraries. So each time I setup this project with CMake, I have to set each entry (path of the third party library) on the GUI of CMake. I improve this by making CMake script guess the path by this script (learn this technique from OGRE):
# Guess the paths.
set( OGRE_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/Dependencies/Ogre" CACHE STRING "Path to OGRE source code (see http://www.ogre3d.org/tikiwiki/tiki-index.php?page=CMake+Quick+Start+Guide)" )
So each time I setup with CMake, it will automatic fill the entry OGRE_SOURCE. But that doesn't enough. If the Ogre source is not in the path
"${CMAKE_CURRENT_SOURCE_DIR}/Dependencies/Ogre"
, then I have to open and edit the CMake script or I have to edit the entry on the GUI of CMake. I find that pretty inconvenient, especially when you link to a lot of third party libraries.
So I want to use another technique: preset settings for entries from file - CMake reads the presets from file PresetEntries.txt (that I make) and apply the these presets on the entries (It's a lot quicker to edit the path in text file than on the GUI of CMake).
Here my idea about this preset file: PresetEntries.txt
OGRE_SOURCE=E:/Source/ogre
I found that CMake can read a text file, but if I use this, I have to do string manipulations.
CMake has the file CMakeCache.txt to save the settings on the CMake GUI, but I want it to be simple: it should only has the preset settings that need to be pre-set.
So I wonder if CMake support this preset settings for entries from file.
Edit:
So I read this question and see that CMake can set config from file, but this require to fire cmake with the -C mysettings.cmake, but I wanna it to be automatically with CMake GUI - just edit the file and hit generate button in CMake GUI. So I wanna make this question more specific:
In my CMakeLists.txt should have script like this:
# Guess the paths.
#I wanna have this function from C++
#https://msdn.microsoft.com/en-us/library/windows/desktop/ms724353%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
GetPrivateProfileString("OGRE", #lpAppName
"OGRE_SOURCE", #lpKeyName
"${CMAKE_CURRENT_SOURCE_DIR}/Dependencies/Ogre", #lpDefault
OGRE_SOURCE_VAR,#lpReturnedString
MAX_PATH, #nSize, may be can reduce this variable
"LibPath.ini") #lpFileName
set( OGRE_SOURCE "${OGRE_SOURCE_VAR}" CACHE STRING "Path to OGRE source code" )
In the file LibPath.ini
[OGRE]
OGRE_SOURCE = "E:/Source/ogre"
So the user can choose to either use the ini file or not.
I don't know if there any way I can use a function that similar to function GetPrivateProfileString (of C++) in CMake.
Thanks for reading
The external libraries should be included by one of the following commands
find_package(ttnlib REQUIRED HINTS /usr/local/lib/cmake)
include_directories(${ttnlib_INCLUDE_DIR})
set(EXTRA_LIBS ${EXTRA_LIBS} ${TTNLIB_LIBRARY})
or
find_library(MY_EXTERNAL_LIB name COOLSTUFF libCOOLSTUFF libCOOLSTUF.so hints /usr/local/lib)
The search for the external packages and libraries should only be necessary for the first run of cmake.
I can't find the function to read the ini file, so what I can do is create a simple function that read simple txt file for myself.
I declare the function in 1 file for other file use it
"\CMake\Dependencies\CommonFunc.cmake"
#------------Define function Read file------------
macro( readSettingFile KEY DEFAULT_RESULT STRING_RESULT_OUT)
unset(STRING_RESULT)
# Read the file
file( READ "${CMAKE_SOURCE_DIR}/LibPath.txt" LIB_PATH_STR )
# Set the variable "Esc" to the ASCII value 27 - basically something
# which is unlikely to conflict with anything in the file contents.
string(ASCII 27 Esc)
# Turn the contents into a list of strings, each ending with an Esc.
# This allows us to preserve blank lines in the file since CMake
# automatically prunes empty list items during a foreach loop.
string(REGEX REPLACE "\n" "${Esc};" LIB_PATH_LINES "${LIB_PATH_STR}")
foreach(LINE ${LIB_PATH_LINES})
if("${LINE}" MATCHES "${KEY}")
#remove the key, leave the content untouch
string(REPLACE "${KEY}" "" STRING_RESULT ${LINE})
# Swap the appended Esc character back out in favour of a line feed
string(REGEX REPLACE "${Esc}" "" STRING_RESULT ${STRING_RESULT})
endif()
endforeach()
if("${STRING_RESULT}" STREQUAL "")
set( STRING_RESULT ${DEFAULT_RESULT} )
endif()
#message( STATIC "---GTA Sa-----" "[${STRING_RESULT}]" )
endmacro()
(I need the help from this answer to write this function :p)
Here is how I use
For example: "\CMake\Dependencies\Ogre.cmake"
#include common functions
include( CMake/Dependencies/CommonFunc.cmake )
#---------------Guess the paths.----------------------
#----Set OGRE_SOURCE
readSettingFile( "OGRE_SOURCE="
"E:/Source/ogre"
STRING_RESULT
)
set( OGRE_SOURCE "${STRING_RESULT}" CACHE STRING "Path to OGRE Source" )
#----Set OGRE_BINARIES
readSettingFile( "OGRE_BINARIES="
"E:/Source/_build/ogre"
STRING_RESULT
)
set( OGRE_BINARIES "${STRING_RESULT}" CACHE STRING "Path to OGRE's build folder generated by CMake" )
Here is the setting file
"\LibPath.txt"
OGRE_SOURCE=E:/Source/ogre
OGRE_BINARIES=E:/Source/_build/ogre

CMake: Function is callable while script, defined it, is no longer included

I have three folders in a location, say A,B and C. I have two cmake files in folder A: FindABC.cmake and UseABC.cmake. The former is for finding the libraries and the latter contains a function, say run_command(). CMakelists.txt in folder B and folder C contains the following lines:
find_package(ABC)
include(UseABC)
run_command()
It works as intended. Now If I comment find_package() and include() in CMakelists of folder C, as far as I know, Cmake should give an error telling unknown command - run_command(). But, the controls goes into the function and executes in unpredictable manner.
How come the control goes to the function when the include line is commented? The root CMakelists that lists the sub-directories does not have any find_package or include lines in it.
Edit:
UseABC.cmake:
set(ABC_COMPILE_DEBUG FALSE)
set(ABC_COMPILE_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/abc_gen")
message("USEABC1 - -> " ${ABC_COMPILE_OUTPUT_DIR})
function(run_command)
message("USEABC2 - File recurs -> " ${ABC_COMPILE_OUTPUT_DIR})
file(REMOVE_RECURSE "${ABC_COMPILE_OUTPUT_DIR}")
file(MAKE_DIRECTORY "${ABC_COMPILE_OUTPUT_DIR}")
add_custom_command() #command to be executed
endfunction()
Here, When nothing is commented(find_package and include is not commented in any CMakelists.txt), I get the correct path for the two messages I print.
When I comment include(UseABC) in the second CMakelists.txt, the configuration fails, the first message is not at all printed and the second message gets printed, but does not give the value of the variable. It also deletes all the files in Folder C (but the argument to REMOVE_RECURSE is empty).
If I correctly understand the situation, you have:
CMakeLists.txt:
add_subdirectory(B)
add_subdirectory(C)
B/CMakeLists.txt:
find_package(ABC)
include(UseABC)
In that case run_command function, defined in UseABC.cmake, is accessible in C/CMakeLists.txt, though this script doesn't define it.
In CMake function definitions are global.
By opposite, variable definitions are local to the scope, where they are defined. (Until variables are cached ones, in that case they have global visibility).
That is, variable ABC_COMPILE_DEBUG defined in UseABC.cmake is accessible in
UseABC.cmake script
B/CMakeLists.txt script, because it includes UseABC.cmake one, and include() command doesn't introduce a scope
but it is inaccessible in
CMakeLists.txt script, because add_subdirectory(B) does introduce a scope
C/CMakeLists.txt script
More details about variable's visibility can be found in documentation.

CMake: collecting libraries

I am using CMake to build a simple C++ project, hereafter named P. The structure of P is quite simple:
P/src/
P/src/package1
P/src/packege2
P/src/...
P/src/main-app
I would like to collect the libraries in package1, package2, ... in a variable called P_LIBS.
In a first attempt, I tried to collect the libraries available in package1, package2, ... in the variable called P_LIBS initially set in the src/CMakeLists.txt file. However, the updates to P_LIBS made in the CMakeLists.txt of the subfolders are not propagated to the parent folder.
I would rather not write a list of libraries in the main CMakeLists.txt file. I would rather modify such variable while moving in the directory tree.
After a search on the internet I could not find any valid suggestion. If I look at the various Find files, I only see long listings of libraries in their main CMakeLists.txt file.
Is there a way to do what (I hope) I explained above?
Thanks to sakra's link I was able to 'propagate' names up to the parent folder. However, the names I add to the P_LIBS variable are later interpreted as 'library' names, not as reference to CMake targets. In other words, if
P_LIBS = {a, b}
the 'a' and 'b' are interpreted as the library names, i.e. CMake generates:
gcc [...] -l a -o exe
instead of
gcc [...] /path/to/a.o -o exe
(.o or other extensions)
You are propably constructing the targets list as a string, try to make them a list instead. For example:
# in package1/CMakeLists.txt
set(P_LIBS ${P_LIBS} a b PARENT_SCOPE)