CMakeLists using variables to define source/include locations - cmake

I have an AndroidStudio project with 'C' files in. I can compile and run as-is.
My native files are in
src/main/jni/aes
src/main/jni/libjpeg
src/main/jni/smuglib
I am trying to move the source to a location external to the Android studio project so that I can use it from several locations/projects to avoid copy/paste/mistake cycle.
I have defined the include path in CMakeLists.txt
include_directories(src/main/jni/aes src/main/jni/libjpeg src/main/jni/smuglib)
And have specified the files in the add_library command
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/jni/aes/aes.c
src/main/jni/smuglib/smuglib.c
.... etc
How do I set up a variable to refer to these paths, eg 'src/main/jni/aes' so that I can use it in both the include and in the source list?
I tried variations on
set(aes_src, src/main/jni/aes)
but uses of it as ${aes_src} either in the include path statement or in the source list give me all sorts of arcane errors which I am at a loss to understand.
I will generate some of these and include them if folk think it would help, but I am likely barking up the wrong kettle of fish with this approach.
Is there a better approach?

It is set(VAR_NAME item1 item2 item3). No commas needed.

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: How to reuse source file definitions between targets without duplication?

In my CMake project, I have 2 targets (a static library and a shared library) that share the same source code files, like this:
add_library("${PROJECT_NAME}" STATIC
"${PROJECT_SOURCE_DIR}/src/calculator/core/ShuntingYard.h"
"${PROJECT_SOURCE_DIR}/src/calculator/core/ShuntingYard.cpp"
"${PROJECT_SOURCE_DIR}/include/calculator/core/Calculator.h"
"${PROJECT_SOURCE_DIR}/src/calculator/core/Calculator.cpp"
)
add_library("${PROJECT_NAME}-shared" SHARED
"${PROJECT_SOURCE_DIR}/src/calculator/core/ShuntingYard.h"
"${PROJECT_SOURCE_DIR}/src/calculator/core/ShuntingYard.cpp"
"${PROJECT_SOURCE_DIR}/include/calculator/core/Calculator.h"
"${PROJECT_SOURCE_DIR}/src/calculator/core/Calculator.cpp"
)
Obviously, there is a problem here: the sources definition is duplicated. It's hard to maintain and it's also error prone.
In order to avoid that, I'd like to create a CMake list variable so that the sources definition could be reused in both targets.
I've tried this but it doesn't work:
set(CALCULATOR_CORE_SOURCES_LIST
"${PROJECT_SOURCE_DIR}/src/calculator/core/ShuntingYard.h"
"${PROJECT_SOURCE_DIR}/src/calculator/core/ShuntingYard.cpp"
"${PROJECT_SOURCE_DIR}/include/calculator/core/Calculator.h"
"${PROJECT_SOURCE_DIR}/src/calculator/core/Calculator.cpp"
)
string(REPLACE ";" " " CALCULATOR_CORE_SOURCES "${CALCULATOR_CORE_SOURCES_LIST}")
add_library("${PROJECT_NAME}" STATIC ${CALCULATOR_CORE_SOURCES})
add_library("${PROJECT_NAME}-shared" SHARED ${CALCULATOR_CORE_SOURCES})
It fails with the error: Cannot find source file.
So... how could I reuse source file definitions between targets without this duplication? Is it possible to do this using lists or is there a better approach to solve this issue?
PS: I'm using CMake 3.15
Your code is close; you can simply use the CALCULATOR_CORE_SOURCES_LIST variable to add the group of sources/headers to both add_library() calls:
set(CALCULATOR_CORE_SOURCES_LIST
${PROJECT_SOURCE_DIR}/src/calculator/core/ShuntingYard.h
${PROJECT_SOURCE_DIR}/src/calculator/core/ShuntingYard.cpp
${PROJECT_SOURCE_DIR}/include/calculator/core/Calculator.h
${PROJECT_SOURCE_DIR}/src/calculator/core/Calculator.cpp
)
add_library(${PROJECT_NAME} STATIC ${CALCULATOR_CORE_SOURCES_LIST})
add_library(${PROJECT_NAME}-shared SHARED ${CALCULATOR_CORE_SOURCES_LIST})
If the group of sources is the same for both libraries, you should only need to define the list once. From the documentation, the set command will do the following:
Multiple arguments will be joined as a semicolon-separated list to form the actual variable value to be set.
Thus, this list can be passed to the add_library() calls. You also shouldn't need the quotes (") around each file.

CMake: Managing a list of source files

The problem I'm having at the moment is that I simply wish to manage my list of source files by grabbing everything and removing the few odds and ends that I do not need. I was hoping that Cmake provided nice built-in tools for this.
So I might start with:
file(GLOB A "Application/*.cpp")
I feel like I want to create another list of files to be removed and I want to tell CMake: Remove from list A items that are in list B.
If this were Python I might do something like:
C = [f for f in A if f not in B]
I may have screwed that syntax up but I'm wondering if there is built-in support for managing these lists of files in a more elegant way?
Even if I could do something like my Python example, A is list of absolute paths so constructing B is clunky.
And why absolute paths anyway? It seems like this will break your build as soon as you relocate the source.
You can do that by using the list command with the REMOVE_ITEM option:
list(REMOVE_ITEM <list> <value> [<value> ...])
Have a look:
file(GLOB FOO *)
set (ITEMS_TO_REMOVE "item;item2;item3")
message(STATUS "FOO is ${FOO}")
list(REMOVE_ITEM FOO ${ITEMS_TO_REMOVE})
message(STATUS "FOO is now ${FOO}")
Keep in mind that the paths returned by file(GLOB) are absolute, you might want to build your list of items to remove by prepending ${CMAKE_CURRENT_LIST_DIR} to each one of them:
set (ITEMS_TO_REMOVE "${CMAKE_CURRENT_LIST_DIR}/item;
${CMAKE_CURRENT_LIST_DIR}/item2;
${CMAKE_CURRENT_LIST_DIR}/item3")
If you like Python, you can generate your list of source files with execute_process. There is also possiblity to work with lists.
But I would recommend you to "hardcode" your list of source files.
File command documentation states:
We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate.

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)

Cmake script problems find_path

I have put these two lines in my Findglm.cmake file to point to the headers for this header library.
find_path(glm_INCLUDE_DIR NAMES glm.hpp matrix_transform.hpp type_ptr.hpp PATHS
${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm ${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm/gtc
${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm/gtx ${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2glm/core)
set(glm_INCLUDE_DIRS ${glm_INCLUDE_DIR})
However when I generate my Xcode project it says that it cannot locate matrix_transform.hpp and type_ptr.hpp
I have played around with this some more it appears to only find the first argument I am wondering if I am using find path wrong ?
I am using cmake 2.8.8 darwinports.
The find_path() command returns single directory. In your case, it's the first dir, which contains the first file.
If this glm will be always located in your source dir, it would be sufficient to do
include_directories(${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm
${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm/gtc
${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm/gtx
${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm/core)
The find_path() is used to determine dir somewhere outside of your project.