CMake - get_filename_component Unknown component directory - c++

I am having a bit of trouble with CMake. I am trying to link with GLFW and include multiple source files of my own project. (I'm switching from Visual Studio to make my project cross-platform).
GLFW is in the folder deps/glfw-3.1.1 and my source code is in the folder src
Here is my CMakeLists.txt file:
# Tell CMake to use a minimum of version 3.2
cmake_minimum_required(3.2)
project(Sparky)
# TODO: Versions
# Add all of our source code to the project
file(GLOB_RECURSE Sparky_SOURCES "src/*.cpp")
file(GLOB_RECURSE Sparky_HEADERS "src/*.h")
set(Sparky_INCLUDE_DIRS "")
foreach (_headerFile ${Sparky_HEADERS})
get_filename_component(_dir ${_headerFile} path)
list (APPEND Sparky_INCLUDE_DIRS ${_dir})
endforeach()
list(REMOVE_DUPLICATES Sparky_INCLUDE_DIRS)
add_subdirectory(deps/glfw-3.1.1)
include_directories(${Sparky_INCLUDE_DIRS})
include_directories(deps/glfw-3.1.1/include)
add_executable(Sparky ${Sparky_SOURCES}
target_link_libraries(Sparky glfw ${GLFW_LIBRARIES}))

It seems that there is at least an iteration with wrong values for variables _headerFile and path. Try to print values of these variables before launching get_filename_component in the foreach loop using the following code.
message(STATUS "_headerFile: ${_headerFile} )
message(STATUS "path: " ${path} )
Sometimes these types of errors can be generated by wrong values of these parameters.

It is common to see this error with "multiple inclusions" of *Config.cmake files (e.g. you run CMake for lib_A which uses both lib_B and lib_C while lib_B also links to lib_C).
You can detect this behaviour through CMake messages:
message(STATUS "_headerFile: ${_headerFile} )
message(STATUS "path: " ${path} )
Then the output will be displayed twice or more, probably with different values each time it enters the *Config.cmake file.
You can easily solve the problem using IF statements (think of the #ifndef in C headers):
IF (MYPKG_FOUND)
# Already in cache, be silent
SET(MYPKG_FIND_QUIETLY TRUE)
ELSE (EdgeFlow_FOUND)
# do your stuff, you're here for the first time!
ENDIF(MYPKG_FOUND)

For me this error was caused by putting list into get_filename_component().
Example:
set(abc /path/first /path/second)
get_filename_component(abc_name ${abc} NAME)
The error will look like:
get_filename_component unknown component /path/second

Related

OpenSceneGraph plugin not included in Conan?

I'm trying to do simple mesh viewer using OpenSceneGraph and I want to use Conan for dependencies.
The compilation is working well in both debug and release mode (I'm compiling on Windows for now with msvc toolchain).
As soon as I try to load any kind of mesh, the osgDB::readNodeFiles just fail. Looks like the plugin are not linked to the final binary.
I checked in the Conan's package, the plugin list of .lib exists and are supposed to be linked I guess.
What could I miss ?
There is my conanfile.txt :
[requires]
openscenegraph/3.6.5
[generators]
cmake
The CMakeLists.txt is also straightforward :
cmake_minimum_required(VERSION 3.17)
# Set a default build type if none was specified
set(default_build_type "Release")
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE
STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
set(PROJECT_NAME 3D_radio)
project(${PROJECT_NAME})
if(EXISTS ${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
set(CMAKE_CONFIGURATION_TYPES ${CONAN_CONFIGURATION_TYPES})
else()
message(WARNING "The file conanbuildinfo.cmake doesn't exist, you have to run conan install first")
endif()
# get all source files
file(GLOB all_SRCS
"include/*.h"
"source/*.cpp"
)
# add executable and addShader libraries
add_executable(${PROJECT_NAME} ${all_SRCS} source/main.cpp include/main.h)
target_include_directories(${PROJECT_NAME} PRIVATE
include
${CONAN_INCLUDE_DIRS}
)
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
And the code is also very simple :
int main(int argc, char **argv) {
// use an ArgumentParser object to manage the program arguments.
osg::ArgumentParser arguments(&argc,argv);
// read the scene from the list of file specified commandline args.
osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
// if not loaded assume no arguments passed in, try use default mode instead.
if (!loadedModel) loadedModel = osgDB::readNodeFile("cow.osgt");
// if no model has been successfully loaded report failure.
if (!loadedModel)
{
std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
return 1;
}
}
The console output :
C:\...\cmake-build-release\bin\program.exe C:\...\first.obj
C:\...\cmake-build-release\bin\program.exe: No data loaded
Error reading file C:\...\first.obj: read error (Could not find plugin to read objects from file "C:\...\first.obj".)
Error reading file cow.osgt: read error (Could not find plugin to read objects from file "cow.osgt".)
I have no problem to open those files in Paint 3D for example. So I know they are correct. The problem looks to come from linking. Any idea ?
I found the solution.
I'm compiling statically the program, the plugins are linked to the final binary but the plugin registry look for a dynamic library (osgdb_obj.dll for example).
If you have the same problem, you have to register manually the plugin :
USE_OSGPLUGIN(obj)
USE_GRAPHICSWINDOW() // and you may want this to get a window
The "plugin list of .lib" which you highlighted are, unlike static libs, import libraries which will introduce a dynamic DLL dependency in the final link. The plugin DLLs still have to be present somewhere from where the linker can then load them off, at runtime. OSG plugins are typically loaded relative to the value of OSG_LIBRARY_PATH env variable. Setting this to the folder holding the, say "osgPlugins-3.6.5" directory, should successfully load the plugins.
SET OSG_LIBRARY_PATH=C:\TOOLS\vcpkg\installed\x64-windows\debug\plugins\
Few things which could still break this are: Debug/Release plugins mismatch and some spurious space in the OSG_LIBRARY_PATH env variable, like this one (logged via SET OSG_NOTIFY_LEVEL=DEBUG)
FindFileInPath() : trying C:\TOOLS\vcpkg\installed\x64-windows\debug\plugins\ \osgPlugins-3.6.5\osgdb_osgd.dll
The space above was present in the OSG_LIBRARY_PATH env

Cant compile OpenCV Source file with my project

This question is a continuation of one I asked before
I have a project that uses the librealsense library and OpenCV. librealsense works but I cannot include OpenCV in my project for the life of me. There is currently only 1 CPP file and 1 HPP file, this is the cmake file of the root
project(peoplecounting)
add_subdirectory(libs/librealsense-master)
add_subdirectory(libs/opencv-4.3.0)
set(OpenCV_DIR ${CMAKE_BINARY_DIR}/libs/opencv-4.3.0)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable (CMakeRealSense "CMakeRealSense.cpp" "CMakeRealSense.h")
find_library(realsense2 HINTS libs/librealsense-master)
find_library(opencv HINTS ${CMAKE_BINARY_DIR}/libs/opencv-4.3.0)
target_link_libraries(CMakeRealSense ${OpenCV_LIBS} realsense2)
I have both source files in a libs folder(so directory would look like root/libs/opencv-4.3.0). I am new to cmake so I just might be missing something but its driving me nuts
Some extra notes
1, OpenCV does build the libs when I can build the project, if I remove any include from my self written code it wont make errors which lets me build the project. This does make the opencv librairys which makes me think the linking is the issue
2, If I dont add a project as a executable it does see a opencv include
3, I am doing this to make the project portable, it has to work on a rpi down the line so being able to build it all from source could make it much more portable
EDIT 1
So I did some diging in my files, the exe gets outputted into
root\out\build\x64-Debug\bin but this folder does not only contain the librealsense dll but also the opencv ones. This would make it seem that the exe knows about the library but doesnt want to use it some how? This is very strange to me too
EDIT 2
I managed to find_package(OpenCV) by setting
CMAKE_PREFIX_PATH to win-install which contained a config file, problem now is that iam missing the include dir in said folder
EDIT 3
New error seems to be
Target "opencv_highgui" INTERFACE_INCLUDE_DIRECTORIES property contains
path:
"root/opencv-4.3.0/modules/dnn/include"
which is prefixed in the source directory.
I read somewhere that OpenCV prevents source files being used or something to prevent corruption but now now again at a end when it comes to what iam suppose to be doing
Updated CMake file
project(peoplecounting)
add_subdirectory(librealsense-master)
add_subdirectory(opencv-4.3.0)
set(OpenCV_DIR ${CMAKE_BINARY_DIR})
set(INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_BINARY_DIR}/")
set(BUILD_SHARED_LIBS OFF)
find_package(OpenCV CONFIG REQUIRED)
add_library(opencv INTERFACE)
include_directories(${OpenCV_INCLUDE_DIRS})
#add_executable (CMakeRealSense "CMakeRealSense.cpp" "CMakeRealSense.h")
add_executable(RealSenseTest "TestRealSense.cpp")
find_library(realsense2 HINTS librealsense-master)
message(" cv_libs: " ${OpenCV_INSTALL_PATH})
message(" cv_includes: " ${OPENCV_INCLUDE_DIRS})
target_include_directories(opencv INTERFACE "${OpenCV_INCLUDE_DIRS}")
target_link_libraries(RealSenseTest "${OpenCV_LIBS}" realsense2)```

CMake - add_executable called with incorrect number of arguments

I am trying to organize a C++ project which starts to have a lot of files. I would like to create two executables which share some source file using Cmake. I have found an interesting procedure here:
How to add source files in another folder
Below is my version of the thing
file(GLOB Common_sources RELATIVE "Common" "*cpp")
file(GLOB Mps_sources RELATIVE "Mps" "*.cpp")
file(GLOB Mss_sources RELATIVE "Mss" "*.cpp")
add_executable(test_mss ${Common_sources} ${Mss_sources})
add_executable(test_mps ${Common_sources} ${Mps_sources})
But CMake complains
CMake Error at src/CMakeLists.txt:44 (add_executable):
add_executable called with incorrect number of arguments
CMake Error at src/CMakeLists.txt:45 (add_executable):
add_executable called with incorrect number of arguments
It says to look at CMakeOutput.log, but the file is really too long, I can not find useful information.
I checked the CMake documentation, it seems that it can take a second source as an additional argument. https://cmake.org/cmake/help/v3.0/command/add_executable.html
I would like to find the source of this bug. I have the feeling that I am missing something obvious here.
The error you get is because source list, passed to add_executable, is actually empty.
Correct way for collect sources in Common/ subdirectory is:
file(GLOB Common_sources "Common/*.cpp")
In command file(GLOB) RELATIVE option doesn't specify search directory. Instead, it just tells CMake to generate relative paths instead of absolute:
If RELATIVE flag is specified, the results will be returned as relative paths to the given path.
Assuming
file(GLOB Common_sources "Common/*.cpp")
# gets: /<path-to-source>/Common/my_source.cpp
then (also note to absolute path in RELATIVE option)
file(GLOB Common_sources RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/Common" "Common/*.cpp")
# gets: my_source.cpp
and (when files are not under RELATIVE directory)
file(GLOB Common_sources RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/Mps" "Common/*.cpp")
# gets: ../Common/my_source.cpp
You have to quote the variables.
add_executable(test_mss "${Common_sources}" "${Mss_sources}")
Otherwise for an empty variable, CMake replaces the variable by nothing and the number of arguments seems to be wrong.
Similar problem: https://stackoverflow.com/a/39733128/2799037
None of the suggested answers worked for me.
This works:
add_executable(<executable_name> <source_file_name>)

Building specialized service APIs in google-api-cpp-client

I'm trying to build the specialized Youtube API, which is included in the standard distribution of the google-api-cpp-client library. The documentation states:
If you download the C++ libraries and unzip them into the service_apis directory at the root of the source installation for this SDK then the default build scripts will automatically build them.
However, the build scripts do not. Building the samples which are included in the distribution reveals this quite clearly.
Linking CXX executable ../../bin/calendar_sample
ld: library not found for -lgoogle_calendar_api
The tail of the root CMakeLists.txt reads as follows:
add_subdirectory(src)
if (googleapis_build_samples)
set(googleapis_build_service_apis true) # force on
endif()
if (googleapis_build_service_apis)
add_subdirectory(service_apis)
endif()
# Build samples after the service apis
# but keep them under src
if (googleapis_build_samples)
add_subdirectory(src/samples)
endif()
Which eventually leads to this CMakeLists.txt (in the root of the service_apis directory):
file(GLOB all_valid_subdirs RELATIVE
${CMAKE_CURRENT_SOURCE_DIR} "*/CMakeLists.txt")
foreach(dir ${all_valid_subdirs})
message(STATUS "path = ${dir}")
if(${dir} MATCHES "^([^/]*)//CMakeLists.txt")
string(REGEX REPLACE
"^([^/]*)//CMakeLists.txt" "\\1" dir_trimmed ${dir})
add_subdirectory(${dir_trimmed})
endif()
endforeach(dir)
I've put a message output inside the if statement. It seems the add_subdirectory call is never reached. The foreach does iterate through all the subdirectories though.
Why does the regex comparison fail?
I've actually found the error while finishing up this question. The regex comparison contains an extra forward slash. The following regex will successfully include the libraries.
^([^/]*)/CMakeLists.txt
I will raise a bug with the developer.

Finding a directory in CMake

The problem:
I want to add the boost numeric bindings as an include directory in my build. This is typically compiled as:
c++ -I/where/you/want/to/install/it/include/boost-numeric-bindings
All of the header files I reference from my program are all relative to this directory, so in CMake I want to find this directory (wherever it is installed on the parent system) and add it to the include_directories.
What I'm looking for:
Something like this:
find_directory(BNB_INCLUDE_DIR boost-numeric-bindings)
include_directories(${BNB_INCLUDE_DIR})
But the find_directory command does not exist. Am I missing something here?
What I've tried:
I've tried:
find_path(BNB_INCLUDE_DIR boost/numeric/bindings/traits/ublas_vector.hpp)
include_directories(${BNB_INCLUDE_DIR})
(which is the first file I need from the library) but this gives me the full path to the file and not the path to the directory containing the entire prefix to the file specified in the command.
See this answer for information on how to write a cmake Find file. As an example, here is one that I wrote for the lm-sensors library:
# - Try to find the LM_SENSORS library.
#
# The following are set after configuration is done:
# LM_SENSORS_FOUND
# LM_SENSORS_INCLUDE_DIRS
# LM_SENSORS_LIBRARY_DIRS
# LM_SENSORS_LIBRARIES
find_path(LM_SENSORS_INCLUDE_DIR NAMES sensors/sensors.h)
find_library(LM_SENSORS_LIBRARY NAMES libsensors sensors)
message("LM_SENSORS include dir = ${LM_SENSORS_INCLUDE_DIR}")
message("LM_SENSORS lib = ${LM_SENSORS_LIBRARY}")
set(LM_SENSORS_LIBRARIES ${LM_SENSORS_LIBRARY})
set(LM_SENSORS_INCLUDE_DIRS ${LM_SENSORS_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
# Handle the QUIETLY and REQUIRED arguments and set the LM_SENSORS_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args(LM_SENSORS DEFAULT_MSG
LM_SENSORS_LIBRARY LM_SENSORS_INCLUDE_DIR)
mark_as_advanced(LM_SENSORS_INCLUDE_DIR LM_SENSORS_LIBRARY)
Change the above to match your library (boost-numeric-bindings), name the file Findboost-numeric-bindings.cmake, and put it in your cmake module dir (or create one of these in your source tree).
Then in your CMakeLists.txt file, do this:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} your_cmake_module_dir)
find_package (boost-numeric-bindings REQUIRED)
include_directories(${BOOST_NUMERIC_BINDINGS_INCLUDE_DIR})
Then, assuming you don't have the library installed in a standard location, run cmake as follows:
cmake -D CMAKE_PREFIX_PATH:STRING="/where/you/have/installed/it/" <source path>
Edit
Make sure you have defined a project before you call find_path or find_package. Otherwise CMAKE_SYSTEM_INCLUDE_PATH will not be set. For example:
find_path (BOOST_STATE_HPP boost/statechart/state.hpp)
message ("CMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH}")
message ("CMAKE_SYSTEM_INCLUDE_PATH=${CMAKE_SYSTEM_INCLUDE_PATH}")
message ("CMAKE_SYSTEM_FRAMEWORK_PATH=${CMAKE_SYSTEM_FRAMEWORK_PATH}")
message ("CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}")
message ("BOOST_STATE_HPP=${BOOST_STATE_HPP}")
project (my_project)
will result in the following cmake output:
CMAKE_FIND_ROOT_PATH=
CMAKE_SYSTEM_INCLUDE_PATH=
CMAKE_SYSTEM_FRAMEWORK_PATH=
CMAKE_PREFIX_PATH=
BOOST_STATE_HPP=BOOST_STATE_HPP-NOTFOUND
whereas this:
project (my_project)
find_path (BOOST_STATE_HPP boost/statechart/state.hpp)
message ("CMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH}")
message ("CMAKE_SYSTEM_INCLUDE_PATH=${CMAKE_SYSTEM_INCLUDE_PATH}")
message ("CMAKE_SYSTEM_FRAMEWORK_PATH=${CMAKE_SYSTEM_FRAMEWORK_PATH}")
message ("CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}")
message ("BOOST_STATE_HPP=${BOOST_STATE_HPP}")
results in sucessfully finding state.hpp and setting BOOST_STATE_HPP to /usr/include, as you desire:
CMAKE_FIND_ROOT_PATH=
CMAKE_SYSTEM_INCLUDE_PATH=/usr/include/w32api;/usr/X11R6/include;/usr/include/X11;/usr/pkg/include;/opt/csw/include;/opt/include;/usr/openwin/include
CMAKE_SYSTEM_FRAMEWORK_PATH=
CMAKE_PREFIX_PATH=
BOOST_STATE_HPP=/usr/include