ExternalProject_add: Some files are not copied with INSTALL_COMMAND - cmake

We have an external project we want to fetch using cmake using ExternalProject_add.
Let's say the external project has a structure:
External_Project
├── myClass.hpp
├── myClass.cpp
├── userOfClass.hpp
├── userOfClass.cpp
We're fetching External_Project using the following:
ExternalProject_add(get_rtpm
PREFIX "${EXTERNAL_PROJECT_PREFIX_DIRECTORY}/my_external_project"
SVN_REPOSITORY "${ZE_MIRROR}/${EXTERNAL_PROJECT_SVN_PATH}" --no-auth-cache
SVN_TRUST_CERT 1
SVN_USERNAME "zeUsername"
SVN_PASSWORD "zePassword"
UPDATE_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
BUILD_IN_SOURCE 1
INSTALL_COMMAND cmake -E copy_directory . ${FINAL_LOCATION_DIR}
)
After this we want to move the fetched external project to another location.
So we use
INSTALL_COMMAND cmake -E copy_directory . ${FINAL_LOCATION_DIR}<br>
as seen above.
The files in final location after the INSTALL_COMMAND ends up being:
Final_Location_Dir
├── External_Project
│ ├──myClass.hpp
│ ├── userOfClass.hpp
│ ├── userOfClass.cpp
"myClass.cpp" is missing. Why??
The command includes "copy_directory" but this just one file that's being left out.

Just to clarify on this one.
This was resolved when I fixed one of the misspelled path used in another CMake.
Let's say the FetchMyExternal.cmake is the file with ExternalProject_add.
And a CMakeLists.txt on another that has
add_library(EXTERNAL_LIBRARY
${FINAL_LOCATION_DIR}/myClass.cpp
${FINAL_LOCATION_DIR}/External_Project/myClass.hpp
${FINAL_LOCATION_DIR}/External_Project/userOfClass.cpp
${FINAL_LOCATION_DIR}/External_Project/userOfClass.hpp
)
As you see above, the CMakeLists.txt that creates a library has
a wrong location on one of the files.
The path of myClass.cpp should be
${FINAL_LOCATION_DIR}/External_Project/myClass.cpp
This is a separate CMakeLists.txt file but somehow it causes the the copy_directory of ExternalProject_add to leave out one of the files.
Correcting the location finally copied myClass.cpp to the final location.
Maybe it was "deleted" because the path was wrong? I'm not sure.

Related

Can I make a CMake target dependent upon a target in another CMake project?

I have two separate projects, but one of them must now incorporate aspects of the other, including the generation of some code, which done by a Python script which is called by CMake.
Here is my project structure:
repo/
├── project_top/
│ ├── stuff_and_things.cpp
│ └── CMakeLists.txt
│
└── submods/
└── project_bottom/
├── CMakeLists.txt
└── tools/
├── build_scripts
│ └── cmake_bits.cmake
└── generator
└── gen_code.py
In repo/submods/project_bottom/tools/build_scripts/cmake_bits.cmake there is a macro set_up_additional_targets(), which includes a custom target which runs repo/submods/project_bottom/tools/generator/gen_code.py in that directory. This is based on project_bottom being its own project.
add_custom_target(gen_code
COMMAND echo "Generating code"
COMMAND python3 gen_code.py args
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tools/generator
)
Now, I need to make a new target in project_top dependent upon the gen_code target in project_bottom. How do I do this? The gen_code target needs to be run as part of the project_top build, but within the context of project_bottom, because for that target, ${CMAKE_CURRENT_SOURCE_DIR} needs to be repo/submods/project_bottom, not repo/project_top.

Bitbake create cmake recipe from local sources

I'm trying to build a helloworld package example with a cmake recipe. My problem is bitbake give me an error because it can't find CMakeLists.txt in the /tmp/work/core2-64-poky-linux/helloworld/0.1-r0 folder.
The error :
helloworld-0.1-r0 do_configure: Execution of '/path-to-tmp/tmp/work/core2-64-poky-linux/helloworld/0.1-r0/temp/run.do_configure.28001' failed with exit code 1:
CMake Error: The source directory "/path-to-tmp/tmp/work/core2-64-poky-linux/helloworld/0.1-r0/files" does not appear to contain CMakeLists.txt.
My package is in my layer meta-mylayer/recipes-core/helloworld :
meta-mylayer/
├── conf
│   └── layer.conf
├── COPYING.MIT
├── README
└── recipes-core
└── helloworld
   ├── files
   │   ├── CMakeLists.txt
   │   └── main_helloworld.c
   └── helloworld_0.1.bb
My CMakeLists.txt :
cmake_minimum_required(VERSION 2.4)
project(helloworld)
file(GLOB_RECURSE files/*.c)
add_executable(app ${src_files})
install(TARGETS helloworld DESTINATION bin)
My helloworld_0.1.bb :
PN="helloworld"
PV="0.1"
P="${PN}-${PV}"
DESCRIPTION="This is my package helloworld"
LICENSE="CLOSED"
FILESEXTRAPATHS_prepend:="${THISDIR}/${PN}:"
RDEPENDS_${PN}+=""
DEPENDS+=""
DEPENDS+="cmake"
SRC_URI+="file://CMakeLists.txt file://main_helloworld.c"
S="${WORKDIR}/files"
inherit pkgconfig cmake
I can't find my files in /path-to-tmp/tmp/work/core2-64-poky-linux/helloworld/0.1-r0/*
Why files are not copied? I'm using yocto Dunfell.
Thanks for your help.
When you have files in SRC_URI they are installed in ${WORKDIR}.
The following recipe will do the trick:
DESCRIPTION="This is my package helloworld"
LICENSE="CLOSED"
SRC_URI+="file://CMakeLists.txt file://main_helloworld.c"
S="${WORKDIR}"
inherit pkgconfig cmake
Also, your CMakeLists.txt should not find files in files directory.
S is set to ${WORKDIR} because this is where the files from the file:// fetcher are put by default.
DEPENDS already has cmake-native in it from the cmake bbclass you inherited. You don't need to depends on cmake, because you depends on cmake-native (you need to execute cmake at build time, you don't need cmake headers or sources).
The FILESEXTRAPATHS that was added is already by default used by bitbake (and it's also not matching your directory layout).
PN and PV are gotten from the filename of the bb recipe, no need to set them again.

Using CMake GLOB_RECURSE to find directories

I have the following directory structure:
.
├── CMakeLists.txt
└── deps
├── eigen
│   └── include
│   ├── Eigen
│   └── eigen.h
└── osg
├── include
│   └── Osg
└── lib
└── libosg.so
I am trying to get a maximum of the files I don't need to deploy my software, i.e. the libraries.
I tried to create a globbing expression that matches the *.h files and the include directories:
file(GLOB_RECURSE
FOUND_FILES
LIST_DIRECTORIES true
${CMAKE_SOURCE_DIR}/deps/*/include
${CMAKE_SOURCE_DIR}/deps/*/*.h)
message(STATUS "Files are ${FOUND_FILES}")
However, for some reason, the variable FOUND_FILES contains deps/osg/lib. What did I not understand about the GLOB_RECURSE function?
- deps/eigen/include
- deps/eigen/include/eigen.h
- deps/osg/include
- deps/osg/lib
- deps/eigen/include
- deps/osg/include
- deps/osg/lib
I think this could be a workaround:
file(GLOB_RECURSE
FOUND_FILES
LIST_DIRECTORIES true
${CMAKE_SOURCE_DIR}/deps/*/include
)
list(FILTER FOUND_FILES INCLUDE REGEX "^${CMAKE_SOURCE_DIR}/deps/.*/include$")
file(GLOB_RECURSE
tmp
${CMAKE_BINARY_DIR}/deps/*/*.h
)
list(APPEND FOUND_FILES ${tmp})
I guess this is a bug when GLOB_RECURSE is used with LIST_DIRECTORIES true with an expression that has * not on the last entry in the path. Once a directory containing the matched entry is matched in cmake:Glob.cxx#L404, next directories will be added recursively to the output unconditionally at this add_file() in cmake Glob.cxx#L316. So once a ${CMAKE_SOURCE_DIR}/deps/* directory has a include directory or file inside it, all directories recursively from ${CMAKE_SOURCE_DIR}/deps/ are added to the output. Files are not added, as they are checked against the regex at cmake Glob.cxx:#L326.
It appears that CMake drops the last component of the globbing expression when using GLOB_RECURSE to filter directories. This is why CMake does not filter further for the include directory in your example. This may be a bug in the CMake GLOB_RECURSE implementation for directories, or an oversight in the CMake documentation.
EDIT: Solution 1 (does not work):
You can instead simulate recursion using the globbing pattern itself. Use CMake's GLOB instead, and use ** in the globbing pattern to match on anything with one or more characters between deps/ and /include:
file(GLOB
FOUND_FILES
LIST_DIRECTORIES true
${CMAKE_SOURCE_DIR}/deps/**/include
${CMAKE_BINARY_DIR}/deps/**/*.h)
)
message(STATUS "Files are ${FOUND_FILES}")
Solution 2 (ugly):
You could manually add the levels of directories for CMake to search for include folders:
file(GLOB
FOUND_FILES
LIST_DIRECTORIES true
${CMAKE_SOURCE_DIR}/deps/*/include
${CMAKE_SOURCE_DIR}/deps/*/*/include
...
)
However, this is not a very scalable solution.

Getting sysroot directory with cmake in yocto

I have a few libraries/applications (supplied by a third party vendor, so changing them is not really an option) that are built in a non standard way. Basically, there are libraries that link to other libraries in a weird way.
Here's what I'm talking about:
.
├── libA
│   ├── include
│   │   └── headerA.h
│   └── src
└── libB
   ├── include
   │   └── headerB.h
   └── src
libA includes libB headers using the "" syntax, i.e. #include "headerB.h
" and -I compile option is passed to include the libB/include/ directory. However, linking to libA poses a problem, because I need to include libB include directory as well.
That's not a huge problem, because the headers get installed into the targets sysroot. Let's say the libB headers are installed into ${SYSROOT}/usr/include/libB.
Now, for some reason the sysroot directory is passed using the ${CMAKE_C_FLAGS} instead of ${CMAKE_SYSROOT} as it probably should. I tried parsing ${CMAKE_C_FLAGS} to get the sysroot like this:
execute_process(COMMAND "echo \"${CMAKE_C_FLAGS}\""
COMMAND "grep -Eo '\\-\\-sysroot=\\S*'"
COMMAND "sed 's:--sysroot=::g'"
OUTPUT_VARIABLE SYSROOT
RESULT_VARIABLE SYSROOT_RESULT
)
However, this always fails with "No such file or directory". I figured it's failing to one of the commands, i.e. either echo, grep or sed. How do I fix this? Or maybe there's a better way altogether?

Installing cmake components into different directory

Let's say I have some component install rules for some executables:
install(TARGETS foo1 DESTINATION bin COMPONENT foo-utils)
install(TARGETS foo2 DESTINATION bin COMPONENT foo-utils)
install(TARGETS foo3 DESTINATION bin COMPONENT foo-utils)
Now, I have my own executable, and I want its install rule to also install all the foo-utils install rules - but instead of bin, I want them to go somewhere else.
add_executable(special ...)
# more options
add_dependencies(special foo1 foo2 foo3)
install(TARGETS special DESTINATION package/bin COMPONENT special)
add_custom_target(package-special
DEPENDS special
COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=special -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=foo-utils -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
)
This works great, except building package-special produces:
$ tree install
install
├── bin
│   ├── foo1
│   ├── foo2
│   └── foo3
└── package
└── bin
└── special
How do I get it to produce:
$ tree install
install
└── package
└── bin
├── foo1
├── foo2
├── foo3
└── special
I will have multiple different specials that depend on the foo-utils, and I would like each package-special to install the foo-utils into a different directory. The foo-utils are also in a separate project from the specials, so I cannot install(TARGETS ...) the foo-utils.
cmake_install.cmake uses a default install prefix if one doesn't already exist.
# Set the install prefix
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
set(CMAKE_INSTALL_PREFIX "/usr/local")
endif()
As such, you can specify a value prior to calling the script for your foo-utils installation command.
add_custom_target(package-special
DEPENDS special
COMMAND "${CMAKE_COMMAND}"
-DCMAKE_INSTALL_COMPONENT=special
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
COMMAND "${CMAKE_COMMAND}"
-DCMAKE_INSTALL_COMPONENT=foo-utils
-DCMAKE_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}/package/bin" # <-- here
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
)