C++: How to properly link compiled object using CMake in VSCode - c++

OS
Windows 10
CMake: 3.16.3
Editor
VSCode: 1.48.1
Extensions
CMake Tools: 1.4.1
C/C++ 0.30.0-insiders3
Kit
Visual Studio Community 2019 Release - amd64
Project Repo
https://gitlab.com/NumeralRocket/kepler Removed, insufficient for minimal reproducible example
Tutorial
Introduction to Google Test and CMake
https://www.youtube.com/watch?v=Lp1ifh9TuFI
I'm attempting to build unit tests for one of my personal projects using CMake, and while I wholly admit I am quite new to CMake and a novice at C++, I am stumped on how to resolve this problem. When I go to build my project I get the following Linker error:
[main] Building folder: kepler
[build] Starting build
[proc] Executing command: "C:\Program Files\CMake\bin\cmake.EXE" --build n:/Unreal_Engine/Magellan/kepler/build-vscode --config Debug --target ALL_BUILD -- /maxcpucount:14
[build] Microsoft (R) Build Engine version 16.6.0+5ff7b0c9e for .NET Framework
[build] Copyright (C) Microsoft Corporation. All rights reserved.
[build]
[build] gmock.vcxproj -> N:\Unreal_Engine\Magellan\kepler\build-vscode\lib\Debug\gmockd.lib
[build] gmock_main.vcxproj -> N:\Unreal_Engine\Magellan\kepler\build-vscode\lib\Debug\gmock_maind.lib
[build] kepler.vcxproj -> N:\Unreal_Engine\Magellan\kepler\build-vscode\Debug\kepler.lib
[build] gtest.vcxproj -> N:\Unreal_Engine\Magellan\kepler\build-vscode\lib\Debug\gtestd.lib
[build] gtest_main.vcxproj -> N:\Unreal_Engine\Magellan\kepler\build-vscode\lib\Debug\gtest_maind.lib
[build] LINK : fatal error LNK1104: cannot open file 'Quaternion.lib' [N:\Unreal_Engine\Magellan\kepler\build-vscode\test\QuaternionTests.vcxproj]
[cmakefileapi-parser] Code model version (2.1) of cmake-file-api is unexpected. Expecting (2.0). IntelliSense configuration may be incorrect.
[cmakefileapi-parser] Code model version (2.1) of cmake-file-api is unexpected. Expecting (2.0). IntelliSense configuration may be incorrect.
[build] Build finished with exit code 1
For context, the project is structured as follows:
${ProjectRoot}
├── CMakeLists.txt
├── Quaternion.cpp
├── Quaternion.hpp
├── googletest
└── test
├── CMakeLists.txt
└── QuaternionTest.cpp
${ProjectRoot}/CMakeLists.txt
cmake_minimum_required(VERSION 3.16) # version can be different
set(CMAKE_VERBOSE_MAKEFILE ON)
set(This kepler)
get_filename_component(CODE_ROOT ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
project(${This}) #name of your project
project(${This} C CXX)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
enable_testing()
add_subdirectory(googletest)
add_subdirectory(test)
set(Headers
Quaternion.hpp
)
set(Sources
Quaternion.cpp
)
add_library(${This} STATIC ${Sources} ${Headers})
${ProjectRoot}/Quaternion.cpp
#include <iostream>
#include "Quaternion.hpp"
// Default Constructor
Quaternion::Quaternion() {}
// Specified Value Constructor
Quaternion::Quaternion(double qs, double qi, double qj, double qk) : q0(qs), q1(qi), q2(qj), q3(qk) {}
Quaternion operator + (Quaternion const &quatA, Quaternion const &quatB) // 1) § 5.3
{
Quaternion quatC;
quatC.q0 = quatA.q0 + quatB.q0;
quatC.q1 = quatA.q1 + quatB.q1;
quatC.q2 = quatA.q2 + quatB.q2;
quatC.q3 = quatA.q3 + quatB.q3;
return quatC;
}
Quaternion operator - (Quaternion const &quatA, Quaternion const &quatB) // 1) § 5.3
{
Quaternion quatC;
quatC.q0 = quatA.q0 - quatB.q0;
quatC.q1 = quatA.q1 - quatB.q1;
quatC.q2 = quatA.q2 - quatB.q2;
quatC.q3 = quatA.q3 - quatB.q3;
return quatC;
}
void QuaternionLog(Quaternion quat2log)
{
std::cout << "q0: " << quat2log.q0 << std::endl;
std::cout << "q1: " << quat2log.q1 << std::endl;
std::cout << "q2: " << quat2log.q2 << std::endl;
std::cout << "q3: " << quat2log.q3 << std::endl;
}
int main()
{
Quaternion quat1;
Quaternion quat2(1, 2, 3, 4);
Quaternion quat3 = quat1 + quat2;
Quaternion quat4 = quat1 - quat2;
QuaternionLog(quat1);
QuaternionLog(quat2);
QuaternionLog(quat3);
QuaternionLog(quat4);
}
${ProjectRoot}/Quaternion.hpp
#ifndef QUATERNION_H
#define QUATERNION_H
class Quaternion
{
public:
double q0{ 1.0 };
double q1{ 0.0 };
double q2{ 0.0 };
double q3{ 0.0 };
Quaternion();
Quaternion(double qs, double qi, double qj, double qk);
friend Quaternion operator + (Quaternion const &quatA, Quaternion const &quatB);
friend Quaternion operator - (Quaternion const &quatA, Quaternion const &quatB);
};
#endif /* QUATERNION_H */
${ProjectRoot}/test/CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
set(This QuaternionTests)
set(Sources
QuaternionTest.cpp
)
add_executable(${This} ${Sources})
target_link_libraries(${This} PUBLIC
gtest_main
Quaternion
)
add_test(
NAME ${This}
COMMAND ${This}
)
${ProjectRoot}/test/QuaternionTest.cpp
#include <gtest/gtest.h>
#include "../Quaternion.hpp"
TEST(Quaternion, QuaternionConstructors)
{
Quaternion test_quat_1;
ASSERT_EQ(test_quat_1.q0, 1);
ASSERT_EQ(test_quat_1.q1, 0);
ASSERT_EQ(test_quat_1.q2, 0);
ASSERT_EQ(test_quat_1.q3, 0);
ASSERT_EQ(1,1);
};
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
};
How can I:
Ensure and Inspect that objects are being built appropriately?
Properly instruct CMake such that the linker can find my Quaternion (source code) object?
Any insight would be appreciated.

My mistake was in adding my library incorrectly:
${ProjectRoot}/CMakeLists.txt
cmake_minimum_required(VERSION 3.16) # version can be different
set(CMAKE_VERBOSE_MAKEFILE ON)
set(This kepler)
get_filename_component(CODE_ROOT ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
project(${This}) #name of your project
project(${This} C CXX)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
enable_testing()
add_subdirectory(googletest)
add_subdirectory(test)
set(Headers
Quaternion.hpp
)
set(Sources
Quaternion.cpp
)
add_library(${This} STATIC ${Sources} ${Headers})
I was adding a library named ${THIS} which was "kepler" instead of the expected "Quaternion", so:
add_library(Quaternion STATIC ${Sources} ${Headers})
correctly tells the linker what/where to expect my library
AND
Leaving a main function in Quaternion.cpp, which was removed
Solution Source: vector-of-bool

Related

Moving from QT 5.12.8 to 5.15.2 MOC fails

We try to mov to the latest Qt 5 LTSB (5.15.2) from our working base Qt 5.12.8 but ran into MOC errors:
The moc process failed to compile
   "SRC:GenericForm.h"
into
   "SRC:moc_GenericForm.cpp"
Output
   SRC:/workspace/NBCI2/src/base/base_language.(9): Parse error at "{"
The problem occours whith every Qt build greater 5.12.x what do we missing? What is changed on moc between 5.12.x and later?
Build system is cmake
base_language is include by some of the include headers.
GenericForm.h:
#pragma once
#include "host.h"
#include "qt_type_defines.h"
#include <qwidget.h>
#include "qt_in_scheduler.h"
#include "qt_out_scheduler.h"
#include "GenericBaseForm.h"
namespace qt
{
using namespace nbc;
class GenericForm : public GenericBaseForm
{
Q_OBJECT
public:
GenericForm(host::ihost * h, const GenericFormConfig & cfg, safe_bool & Shutdown, rmutex & form_creation_mtx);
virtual ~GenericForm();
virtual void SetTitleError(bool on);
virtual void SetTitle(str_cref title_str);
virtual void SetHintText(str_cref hint_str);
virtual bool AllowHide();
virtual void OnLanguageChange(lang_t)
};
}
base_language:
#ifndef BASE_LANGAUAGE_H
#define BASE_LANGAUAGE_H
#include "base.h"
namespace base
{
enum struct lang_t : char
{
default = -1,
english = 0,
german = 1,
french = 2,
};
base::str_t to_string(lang_t);
lang_t from_string(base::str_cref);
}
#endif
CMake.txt:
CMAKE_MINIMUM_REQUIRED(VERSION 3.17.0 FATAL_ERROR)
SET(VERSION_MAJOR 1)
SET(VERSION_MINOR 0)
SET(VERSION_PATCH 0)
SET(PROJECT_NAME "lib_GenericForms")
# find Qt5 and required components
FIND_PACKAGE(Qt5 COMPONENTS REQUIRED Core Gui Widgets )
#need this to include the auto generated ui_mainwindow.h
#file from the qt5_wrap_ui call below.
IF(CMAKE_VERSION VERSION_LESS "3.7.0")
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
ENDIF()
INCLUDE_DIRECTORIES(
)
ADD_DEFINITIONS( -DBUILD_STATIC -DQT_SUPPORT_LIB
)
SET(CMAKE_AUTOMOC ON)
SET(CMAKE_AUTOUIC ON)
SET(CMAKE_AUTORCC ON)
SET(ENVIRONMENT_EXTENSION_DEBUG
${ENVIRONMENT_EXTENSION}
)
SET(ENVIRONMENT_EXTENSION_RELEASE
${ENVIRONMENT_EXTENSION}
)
#set project sources
SET(PROJECT_SOURCES
${CMAKE_CURRENT_LIST_DIR}/GenericBaseForm.h
${CMAKE_CURRENT_LIST_DIR}/GenericBaseForm.cpp
${CMAKE_CURRENT_LIST_DIR}/GenericForm.h
${CMAKE_CURRENT_LIST_DIR}/GenericForm.cpp
${CMAKE_CURRENT_LIST_DIR}/GenericSensorForm.h
${CMAKE_CURRENT_LIST_DIR}/GenericSensorForm.cpp
)
SET(PROJECT_RESOURCES
)
#set project sources
SET(PROJECT_UI
)
# setup project
ADD_LIBRARY(${PROJECT_NAME} STATIC
${PROJECT_SOURCES}
${UI_WRAP}
${MOC_SOURCES}
)
TARGET_LINK_LIBRARIES(
${PROJECT_NAME}
PUBLIC
Qt5::Core
Qt5::Gui
Qt5::Widgets
)
GenerateVSUserFile(
"${ENVIRONMENT_EXTENSION_DEBUG}"
"${ENVIRONMENT_EXTENSION_RELEASE}"
"$(TargetDir)"
"$(TargetDir)"
"$(TargetPath)"
"$(TargetPath)"
""
""
"${PROJECT_NAME}"
)
GenerateVersionInfo(
1
0
0
"${PROJECT_NAME}"
"${PROJECT_NAME}"
"${PROJECT_NAME}.lib"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.rc"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_version.h"
)
# Executables fail to build with Qt 5 in the default configuration
# without -fPIE. We add that here.
set(CMAKE_CXX_FLAGS "${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
#Set the target link subsystem
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS")
#set compiler flasgs
SET(COMPILER_FLAGS "${COMPILER_FLAGS} /MP")
SET(COMPILER_FLAGS "${COMPILER_FLAGS} /EHsc")
SET(COMPILER_FLAGS "${COMPILER_FLAGS} /Zc:wchar_t")
SET(COMPILER_FLAGS "${COMPILER_FLAGS} /wd4290")
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "${COMPILER_FLAGS}")
SET(PROJECT_NAME_INCLUDES ${CMAKE_CURRENT_LIST_DIR} PARENT_SCOPE)
SET(PROJECT_NAME_PROJECTNAME "${PROJECT_NAME}" PARENT_SCOPE)

CMake linking error (undefined reference to function)

I'm working on C/C++ cross platform application. I'm using CMake for build process.
The project structure below is simplified, narrowing to the issue.
├── CMakeLists.txt
├── Common_libs
│ ├── CMakeLists.txt
│ └── File_Process_... (.cc/.h, 4 each)
└── MAIN
├── CMakeLists.txt
└── (Other subdirs and sources/headers)
./CMakeLists.txt:(Common_libs)
# CMakeLists.txt : CMake project, include source and define
# project specific logic here.
#
set(PKG_NAME File_Process)
add_library(${PKG_NAME} STATIC
include/File_Process_Interface.h
include/File_Process_Types.h
include/FP_Directory.h
include/FP_File.h
include/FP_FileLP.h
include/FP_Includes.h
include/Filestruct.h
../../MAIN/error.h
source/File_Process_Factory.cpp
source/FP_Directory.cpp
source/FP_File.cpp
source/FP_FileLP.cpp)
target_include_directories(${PKG_NAME} PUBLIC include)
target_include_directories(${PKG_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/Common/Resources/3RD_PARTYLibrary/include)
if (WIN32)
target_include_directories(${PKG_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/Common/Resources/Windows/Includes)
install(TARGETS ${PKG_NAME} ARCHIVE DESTINATION ${CMAKE_SOURCE_DIR}/Common_libs/dist/${CMAKE_BUILD_TYPE}/Win/)
else()
SET(CMAKE_CXX_FLAGS "-std=c++11")
install(TARGETS ${PKG_NAME} ARCHIVE DESTINATION ${CMAKE_SOURCE_DIR}/Common_libs/dist/${CMAKE_BUILD_TYPE}/Linux/)
endif(WIN32)
target_include_directories(${PKG_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
File_Process_Interface.h
namespace AppExecutable{
namespace Common {
class File_Process_Factory {
public:
enum File_ProcessObjectType {
FP_File, FP_Directory, FP_FileLP, Automatic_Detection
};
static IFile_Process* Create(File_ProcessObjectType type = FP_File, std::string source = "");
};
}
}
File_Process_Factory.cpp
namespace AppExecutable{
namespace Common {
IFile_Process* File_Process_Factory::Create(File_ProcessObjectType type, std::string source) {
switch (type) {
case File_Process_Factory::Automatic_Detection:
struct stat st;
if (stat(source.c_str(), &st) == -1) {
return NULL;
}
else {
if (S_ISDIR(st.st_mode)) {
return (IFile_Process*) (new Common::FP_Directory());
}
else {
if (source.rfind(".xyz") == (source.length() - 4)) {
return (IFile_Process*) (new Common::FP_FileLP());
}
else {
return (IFile_Process*) (new Common::FP_File());
}
}
}
//return (IFile_Process*)new Common::Automatic_Detection();
break;
case File_Process_Factory::FP_File:
return (IFile_Process*) (new Common::FP_File());
break;
case File_Process_Factory::FP_Directory:
return (IFile_Process*) (new Common::FP_Directory());
break;
case File_Process_Factory::FP_FileList:
return (IFile_Process*) (new Common::FP_FileLP());
break;
default:
throw ("Unknown File_ProcessObjectType");
}
}
./CMakeLists.txt:(MAIN)
cmake_minimum_required (VERSION 3.8)
project(AppExecutable C CXX)
cmake_policy(SET CMP0015 NEW)
if (WIN32)
include_directories(MAIN
MAIN/shared)
link_directories(../Common_libs/dist/${CMAKE_BUILD_TYPE}/Win/)
else()
include_directories(MAIN
MAIN/shared)
endif(WIN32)
file(GLOB SOURCES
*.cpp
shared/*.cpp
shared/*.c)
# Add source to this project's executable.
if (WIN32)
add_executable (AppExecutable ${SOURCES})
install(TARGETS AppExecutable DESTINATION ${CMAKE_SOURCE_DIR}/Application/Windows/)
target_link_libraries(AppExecutable File_Process)
else()
add_executable (AppExecutable ${SOURCES})
install(TARGETS AppExecutable DESTINATION ${CMAKE_SOURCE_DIR}/Application/Linux/)
target_link_libraries(AppExecutable File_Process)
endif(WIN32)
SET_TARGET_PROPERTIES(AppExecutable PROPERTIES DEBUG_POSTFIX "_debug")
Finally, when I do make, the following error is generated:
[ 33%] Built target Common_libs
[ 38%] Linking CXX executable AppExecutable
CMakeFiles/AppExecutable.dir/MAIN/FileEntry.cpp.o: In function `AppExecutable::Common::FileEntry::FileSimulation(int, char**)':
FileEntry.cpp:(.text+0xaa9): undefined reference to `AppExecutable::Common::File_Process_Factory::Create(AppExecutable::Common::File_Process_Factory::File_ProcessObjectType, std::string)'
collect2: error: ld returned 1 exit status
make[2]: *** [AppExecutable/AppExecutable] Error 1
make[1]: *** [AppExecutable/CMakeFiles/AppExecutable.dir/all] Error 2
make: *** [all] Error 2
link.txt
/opt/gcc54/bin/g++ -std=c++11 -O3 -DNDEBUG -static-libgcc -static-libstdc++ CMakeFiles/AppExecutable.dir/Output_App.cpp.o CMakeFiles/AppExecutable.dir/FileEntry.cpp.o CMakeFiles/AppExecutable.dir/AppExecutable.cpp.o CMakeFiles/AppExecutable.dir/ABCBaseClass.cpp.o CMakeFiles/AppExecutable.dir/ABCControl.cpp.o CMakeFiles/AppExecutable.dir/shared/CsvReader.c.o CMakeFiles/AppExecutable.dir/shared/OutputInterface.cpp.o CMakeFiles/AppExecutable.dir/shared/DataBlock.cpp.o CMakeFiles/AppExecutable.dir/shared/lElement.cpp.o CMakeFiles/AppExecutable.dir/shared/lParser.cpp.o CMakeFiles/AppExecutable.dir/shared/lParserCApi.cpp.o CMakeFiles/AppExecutable.dir/shared/ssupport.cpp.o CMakeFiles/AppExecutable.dir/shared/lVersionParser.c.o -o AppExecutable ../Common_libs/libFile_Process.a
I'm able to generate executable in Windows, I'm having issue on linux.
I've been trying to fix this for some time. Why it is showing errors if it has already been built before the linkage?

Cannot Open .png file with CImg on CLion (macOS)

I've tried including libpng16/png.h and #define cimg_use_png, but none of them solved the error. Also, I have main.cpp, lenna.jpg and CImg.h in the same directory.
CMakeLists.txt:
cmake_minimum_required(VERSION 3.6)
project(HelloWorld)
set(CMAKE_CXX_STANDARD 17)
set(SOURCE_FILES main.cpp)
add_executable(HelloWorld ${SOURCE_FILES})
set(YOU_NEED_X11 1)
set(YOU_NEED_PNG 1)
if (${YOU_NEED_PNG} EQUAL 1)
message(STATUS "Looking for libpng...")
find_package(PNG REQUIRED)
include_directories(${PNG_INCLUDE_DIR})
target_link_libraries (HelloWorld ${PNG_LIBRARY})
target_compile_definitions(HelloWorld PRIVATE cimg_use_png=1)
endif()
if (${YOU_NEED_X11} EQUAL 1)
message(STATUS "Looking for X11...")
find_package(X11 REQUIRED)
include_directories(${X11_INCLUDE_DIR})
target_link_libraries(HelloWorld ${X11_LIBRARIES})
else()
target_compile_definitions(HelloWorld PRIVATE cimg_display=0)
endif()
main.cpp:
#include <iostream>
#include "CImg.h"
using namespace cimg_library;
int main() {
CImg<unsigned char> img("lenna.png");
int h = img.height();
int w = img.width();
int s = img.spectrum();
std::cout << "h: " << h << " w: " << w << " s: " << s << std::endl;
return 0;
}
The error:
[CImg] *** CImgIOException *** [instance(0,0,0,0,0x0,non-shared)] CImg<unsigned char>::load(): Failed to open file 'lenna.png'.
libc++abi.dylib: terminating with uncaught exception of type cimg_library::CImgIOException: [instance(0,0,0,0,0x0,non-shared)] CImg<unsigned char>::load(): Failed to open file 'lenna.png'.
Process finished with exit code 6
It looks like lenna.png is not being found. Relative paths are relative to the directory containing the executable. That means that if the executable is at cmake-build-debug/HelloWorld and you try to open lenna.png, the file at cmake-build-debug/lenna.png is opened. This means that you should either manually copy lenna.png into cmake-build-debug (I don't recommend this) or ask CMake to do it for you.
Add this to your CMakeLists.txt file.
add_custom_command(
TARGET HelloWorld POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/lenna.png
${CMAKE_BINARY_DIR}/lenna.png
)
This will cause lenna.png to be copied into the same directory as your executable every time the executable is compiled.

c++ Linker error with static library

I am trying to include a static library that I have created with a static method but getting the following error in runtime when trying to invoke the method:
[ INFO] [1528271039.635221775]: Initializing nodelet with 4 worker threads.
/opt/ros/kinetic/lib/nodelet/nodelet: symbol lookup error:/catkin_ws/devel/lib//libmission_manager_nodelet.so: undefined symbol: _ZN14my_commons10ConsoleLog6ROSLogEiNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_
the static library has 2 files:
ConsoleLog.h:
#ifndef CONSOLE_LOG_H
#define CONSOLE_LOG_H
#include "ros/ros.h"
namespace my_commons
{
class ConsoleLog
{
public:
static void ROSLog(int type, std::string message,std::string taskName);
static void STDLog(int logType, std::string msg,std::string taskName);
};
} // namespace my_commons
#endif //CONSOLE_LOG_H
and ConsoleLog.cpp:
#include "ConsoleLog.h"
namespace my_commons
{
void ConsoleLog::ROSLog(int type, std::string message, std::string task)
{
switch (type)
{
case (0):
ROS_DEBUG_STREAM("########## " << task << " DEBUG: " << message << " ##########");
break;
case (1):
ROS_INFO_STREAM("########## " << task << " " << message << " ##########");
break;
case (2):
ROS_WARN_STREAM("########## " << task << " WARNNING: " << message << " ##########");
break;
case (3):
ROS_ERROR_STREAM("########## " << task << " ERROR: " << message << " ##########");
break;
}
}
void ConsoleLog::STDLog(int logType, std::string msg, std::string task)
{
std::cout << msg << std::endl;
}
} // namespace my_commons
the CMakelist.txt:
cmake_minimum_required(VERSION 2.8.3)
project(my_commons)
set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}")
find_package(catkin REQUIRED COMPONENTS
roscpp
)
catkin_package(CATKIN_DEPENDS
INCLUDE_DIRS include)
include_directories(
${catkin_INCLUDE_DIRS}
include/
)
###########
## Build ##
###########
add_library(my_commons
src/ConsoleLog.cpp
)
## Specify libraries to link a library or executable target against
set_target_properties(my_commons PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(my_commons
${catkin_LIBRARIES}
${roscpp_LIBRARIES}
)
#add_dependencies(name_of_package_nodelet)
install(DIRECTORY include/
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
FILES_MATCHING PATTERN "*.h"
PATTERN ".svn" EXCLUDE)
# Install library
install(TARGETS my_commons
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
Edit:
Here is the clients CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.3)
project(my_mission_manager)
set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}")
find_package(catkin REQUIRED COMPONENTS
roscpp
nodelet
std_msgs
my_commons
message_runtime
std_srvs
)
catkin_package(
CATKIN_DEPENDS
message_runtime
std_msgs
my_commons
)
include_directories(
${catkin_INCLUDE_DIRS}
include/
)
###########
## Build ##
###########
add_library(my_mission_manager_nodelet
src/my_mission_manager_nodelet.cpp
)
## Specify libraries to link a library or executable target against
target_link_libraries( my_mission_manager_nodelet
${catkin_LIBRARIES}
${roscpp_LIBRARIES}
)
#add_dependencies(my_mission_manager_nodelet)
# Install library
install(TARGETS my_mission_manager_nodelet
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
# Install header files
install(DIRECTORY src/
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
)
# Install launch files
install(DIRECTORY launch/
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch
)
# Install xml files
install(FILES nodelet_plugins.xml
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
)
What am I missing here?
By the way, I am able to use data from header files in my_commons (enums), the problem occurs when trying to add a cpp file an invoke a static method in it.
Thank you for your help!
Please find below a working example of correct CMake project:
Directory structure:
ROOT
|
+--inc
| +--ConsoleLog.hpp
+--src
| +--ConsoleLog.cpp
| +--main.cpp
+CMakeLists.txt
Your source and header files remains unchanged (I only changed *.h to *.hpp --> after all you write in C++, not C).
main.cpp:
#include "ConsoleLog.hpp"
int main() {
my_commons::ConsoleLog log;
log.ROSLog(1, "xxx", "yyy");
return 0;
}
CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.11)
project(my_commons)
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
find_package(catkin REQUIRED COMPONENTS roscpp)
add_library(my_commons STATIC src/ConsoleLog.cpp)
target_include_directories(my_commons PUBLIC inc ${roscpp_INCLUDE_DIRS})
target_link_libraries(my_commons ${catkin_LIBRARIES} ${roscpp_LIBRARIES})
add_executable(MyExec src/main.cpp)
target_link_libraries(MyExec my_commons)
Result of the execution:
./MyExec
[ INFO] [1528280295.971205050]: ########## yyy xxx ##########
I use newer CMake version to be able to use target_include_directories, because I like this feature. I changed your compiler flags to include C++11 standard, because apparently you use it. I also removed INSTALL CMake rules, because they are irrelevant to the question. Let me know if this answer is OK for you.
=============== EDIT(to answer OP comment)==============
Well, I don't have any problems with embedding this lib in another project structure. The error you got means that your directory structure is incorrect (my_commons dir doesn't exist). Your project tree should look like this:
ROOT
|
+--MyCommonsLib (this is the root of your my_commons library)
|
+--src
| +--main.cpp
+CMakeLists.txt
And your project's CMakeLists.txt might look like this:
cmake_minimum_required(VERSION 2.8.11)
project(SomeSimpleProjectUsingMyCommonsLib)
add_subdirectory(MyCommonsLib)
add_executable(MyExec src/main.cpp)
target_link_libraries(MyExec my_commons)
Just remember to remove the add_executable instruction from your MyCommonLib/CMakeLists.txt. Also main.cpp should be like this:
#include "ConsoleLog.hpp"
int main() {
my_commons::ConsoleLog::ROSLog(1, "xxx", "yyy");
return 0;
}
Sorry, before I didn't notice that ROSLog is declared as static.

Adapting CMakeList.txt to run with CUDA

I'm working with a slam system, i've install dso, which the code can be seen here::
https://github.com/JakobEngel/dso
Everything works fine, I manage to compile and run without errors. But know I want to parallelize the code, using CUDA. I'm having lot's of trouble adapting it's CMakeLists.txt in order to be able to use CUDA. The original CMakeLists from dso is available here:
dso CMakeLists.txt
I'm trying to adapt it basing my changes on this implementation of another author on another SLAM system:
ORB SLAM 2 CMakeLists.txt using CUDA
Right now my CMakeLists, with my changes (not working), is like this:
SET(PROJECT_NAME DSO)
PROJECT(${PROJECT_NAME})
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
#set(CMAKE_VERBOSE_MAKEFILE ON)
set(BUILD_TYPE Release)
#set(BUILD_TYPE RelWithDebInfo)
set(EXECUTABLE_OUTPUT_PATH bin)
set(LIBRARY_OUTPUT_PATH lib)
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
# required libraries
#SET(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "/usr/include")
find_package(SuiteParse REQUIRED)
find_package(Eigen3 REQUIRED)
find_package(Boost)
# optional libraries
find_package(LibZip QUIET)
find_package(Pangolin 0.2 QUIET)
find_package(OpenCV QUIET)
#find_package(OpenACC)
# flags
add_definitions("-DENABLE_SSE")
set(CMAKE_CXX_FLAGS
"${SSE_FLAGS} -O3 -g -std=c++11"
)
set(CMAKE_C_FLAGS
"${SSE_FLAGS} -O3 -g -std=c++11"
)
#LIST(APPEND CMAKE_C_FLAGS "-Wall -Wextra -DUSE_NVTX") <<<< Error: doesn't recognize -Wall -Wextra
#LIST(APPEND CMAKE_CXX_FLAGS "-Wall -Wextra -DUSE_NVTX") << Error: doesn't recognize -Wall -Wextra
find_package(CUDA REQUIRED)
set(CUDA_PROPAGATE_HOST_FLAGS OFF)
SET(CUDA_HOST_COMPILER /usr/bin/g++)
LIST(APPEND CUDA_NVCC_FLAGS "--compiler-options -fno-strict-aliasing -use_fast_math -ccbin gcc-5")
set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -std=c++11")
if (MSVC)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
endif (MSVC)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY lib)
cuda_include_directories(
${CUDA_TOOLKIT_ROOT_DIR}/samples/common/inc
)
# Sources files
set(dso_SOURCE_FILES
${PROJECT_SOURCE_DIR}/src/FullSystem/FullSystem.cpp
${PROJECT_SOURCE_DIR}/src/FullSystem/FullSystemOptimize.cpp
${PROJECT_SOURCE_DIR}/src/FullSystem/FullSystemOptPoint.cpp
${PROJECT_SOURCE_DIR}/src/FullSystem/FullSystemDebugStuff.cpp
${PROJECT_SOURCE_DIR}/src/FullSystem/FullSystemMarginalize.cpp
${PROJECT_SOURCE_DIR}/src/FullSystem/Residuals.cpp
${PROJECT_SOURCE_DIR}/src/FullSystem/CoarseTracker.cpp
${PROJECT_SOURCE_DIR}/src/FullSystem/CoarseInitializer.cpp
${PROJECT_SOURCE_DIR}/src/FullSystem/ImmaturePoint.cpp
${PROJECT_SOURCE_DIR}/src/FullSystem/HessianBlocks.cpp
${PROJECT_SOURCE_DIR}/src/FullSystem/PixelSelector2.cpp
${PROJECT_SOURCE_DIR}/src/OptimizationBackend/EnergyFunctional.cpp
${PROJECT_SOURCE_DIR}/src/OptimizationBackend/AccumulatedTopHessian.cpp
${PROJECT_SOURCE_DIR}/src/OptimizationBackend/AccumulatedSCHessian.cpp
${PROJECT_SOURCE_DIR}/src/OptimizationBackend/EnergyFunctionalStructs.cpp
${PROJECT_SOURCE_DIR}/src/util/settings.cpp
${PROJECT_SOURCE_DIR}/src/util/Undistort.cpp
${PROJECT_SOURCE_DIR}/src/util/globalCalib.cpp
)
include_directories(
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/thirdparty/Sophus
${PROJECT_SOURCE_DIR}/thirdparty/sse2neon
${EIGEN3_INCLUDE_DIR}
)
# decide if we have pangolin
if (Pangolin_FOUND)
message("--- found PANGOLIN, compiling dso_pangolin library.")
include_directories( ${Pangolin_INCLUDE_DIRS} )
set(dso_pangolin_SOURCE_FILES
${PROJECT_SOURCE_DIR}/src/IOWrapper/Pangolin/KeyFrameDisplay.cpp
${PROJECT_SOURCE_DIR}/src/IOWrapper/Pangolin/PangolinDSOViewer.cpp)
set(HAS_PANGOLIN 1)
else ()
message("--- could not find PANGOLIN, not compiling dso_pangolin library.")
message(" this means there will be no 3D display / GUI available for dso_dataset.")
set(dso_pangolin_SOURCE_FILES )
set(HAS_PANGOLIN 0)
endif ()
# decide if we have openCV
if (OpenCV_FOUND)
message("--- found OpenCV, compiling dso_opencv library.")
include_directories( ${OpenCV_INCLUDE_DIRS} )
set(dso_opencv_SOURCE_FILES
${PROJECT_SOURCE_DIR}/src/IOWrapper/OpenCV/ImageDisplay_OpenCV.cpp
${PROJECT_SOURCE_DIR}/src/IOWrapper/OpenCV/ImageRW_OpenCV.cpp)
set(HAS_OPENCV 1)
else ()
message("--- could not find OpenCV, not compiling dso_opencv library.")
message(" this means there will be no image display, and image read / load functionality.")
set(dso_opencv_SOURCE_FILES
${PROJECT_SOURCE_DIR}/src/IOWrapper/ImageDisplay_dummy.cpp
${PROJECT_SOURCE_DIR}/src/IOWrapper/ImageRW_dummy.cpp)
set(HAS_OPENCV 0)
endif ()
# decide if we have ziplib.
if (LIBZIP_LIBRARY)
message("--- found ziplib (${LIBZIP_VERSION}), compiling with zip capability.")
add_definitions(-DHAS_ZIPLIB=1)
include_directories( ${LIBZIP_INCLUDE_DIR_ZIP} ${LIBZIP_INCLUDE_DIR_ZIPCONF} )
else()
message("--- not found ziplib (${LIBZIP_LIBRARY}), compiling without zip capability.")
set(LIBZIP_LIBRARY "")
endif()
# compile main library.
include_directories( ${CSPARSE_INCLUDE_DIR} ${CHOLMOD_INCLUDE_DIR})
cuda_add_library(dso SHARED ${dso_SOURCE_FILES} ${dso_opencv_SOURCE_FILES} ${dso_pangolin_SOURCE_FILES}
${PROJECT_SOURCE_DIR}/src/teste.cu
)
#set_property( TARGET dso APPEND_STRING PROPERTY COMPILE_FLAGS -Wall )
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # OSX
set(BOOST_THREAD_LIBRARY boost_thread-mt)
else()
set(BOOST_THREAD_LIBRARY boost_thread)
endif()
# build main executable (only if we have both OpenCV and Pangolin)
if (OpenCV_FOUND AND Pangolin_FOUND)
message("--- compiling dso_dataset.")
add_executable(dso_dataset ${PROJECT_SOURCE_DIR}/src/main_dso_pangolin.cpp)
target_link_libraries(dso_dataset dso boost_system cxsparse ${BOOST_THREAD_LIBRARY} ${LIBZIP_LIBRARY} ${Pangolin_LIBRARIES} ${OpenCV_LIBS})
else()
message("--- not building dso_dataset, since either don't have openCV or Pangolin.")
endif()
unset(CMAKE_RUNTIME_OUTPUT_DIRECTORY)
So, 'main_dso_pangolin.cpp' is my main file. At this point, with only this changes the code compiles. But i wanted to try if i was able to make some CUDA code. In order to do this I created a 'teste.cu' file, that has the same code as one of the cuda samples, like this:
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
// CUDA runtime
#include </usr/local/cuda-9.0/include/cuda_runtime.h>
#include <cuda.h>
// helper functions and utilities to work with CUDA
#include </usr/local/cuda-9.0/samples/common/inc/helper_functions.h>
#include </usr/local/cuda-9.0/samples/common/inc/helper_cuda.h>
__global__ static void timedReduction(const float *input, float *output, clock_t *timer)
{
// __shared__ float shared[2 * blockDim.x];
extern __shared__ float shared[];
const int tid = threadIdx.x;
const int bid = blockIdx.x;
if (tid == 0) timer[bid] = clock();
// Copy input.
shared[tid] = input[tid];
shared[tid + blockDim.x] = input[tid + blockDim.x];
// Perform reduction to find minimum.
for (int d = blockDim.x; d > 0; d /= 2)
{
__syncthreads();
if (tid < d)
{
float f0 = shared[tid];
float f1 = shared[tid + d];
if (f1 < f0)
{
shared[tid] = f1;
}
}
}
// Write result.
if (tid == 0) output[bid] = shared[0];
__syncthreads();
if (tid == 0) timer[bid+gridDim.x] = clock();
}
#define NUM_BLOCKS 64
#define NUM_THREADS 256
void xx(int argc, char** argv){
printf("CUDA Clock sample\n");
// This will pick the best possible CUDA capable device
int dev = findCudaDevice(argc, (const char **)argv);
float *dinput = NULL;
float *doutput = NULL;
clock_t *dtimer = NULL;
clock_t timer[NUM_BLOCKS * 2];
float input[NUM_THREADS * 2];
for (int i = 0; i < NUM_THREADS * 2; i++)
{
input[i] = (float)i;
}
checkCudaErrors(cudaMalloc((void **)&dinput, sizeof(float) * NUM_THREADS * 2));
checkCudaErrors(cudaMalloc((void **)&doutput, sizeof(float) * NUM_BLOCKS));
checkCudaErrors(cudaMalloc((void **)&dtimer, sizeof(clock_t) * NUM_BLOCKS * 2));
checkCudaErrors(cudaMemcpy(dinput, input, sizeof(float) * NUM_THREADS * 2, cudaMemcpyHostToDevice));
timedReduction<<<NUM_BLOCKS, NUM_THREADS, sizeof(float) * 2 *NUM_THREADS>>>(dinput, doutput, dtimer);
checkCudaErrors(cudaMemcpy(timer, dtimer, sizeof(clock_t) * NUM_BLOCKS * 2, cudaMemcpyDeviceToHost));
checkCudaErrors(cudaFree(dinput));
checkCudaErrors(cudaFree(doutput));
checkCudaErrors(cudaFree(dtimer));
long double avgElapsedClocks = 0;
for (int i = 0; i < NUM_BLOCKS; i++)
{
avgElapsedClocks += (long double) (timer[i + NUM_BLOCKS] - timer[i]);
}
avgElapsedClocks = avgElapsedClocks/NUM_BLOCKS;
printf("Average clocks/block = %Lf\n", avgElapsedClocks);
}
And in my main, the first thing i do is to call this function. This time, when i do 'cmake' and 'make i get errors like:
/home/cesar/Documents/dso/src/teste.cu:18:21: error: ‘threadIdx’ was not declared in this scope
const int tid = threadIdx.x;
/home/cesar/Documents/dso/src/teste.cu:19:21: error: ‘blockIdx’ was not declared in this scope
const int bid = blockIdx.x;
I've install CUDA Toolkit correctly, but here is the version:
cesar#cesar-X550JX:/usr/local/cuda/bin$ /usr/local/cuda/bin/nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2017 NVIDIA Corporation
Built on Fri_Sep__1_21:08:03_CDT_2017
Cuda compilation tools, release 9.0, V9.0.176
What do you think i'm doing wrong or i'm missing? I'm having many difficulties adapting CMakeLists.txt due to its complexity and well defined structure.
--- EDIT ---
Running with make -j VERBOSE=1 i get this messages which tells me that a regular c++ compiler is being used:
/usr/bin/c++ -fPIC -O3 -g -std=c++11 -D_FORCE_INLINES -shared -Wl,-soname,libdso.so -o lib/libdso.so CMakeFiles/dso.dir/src/FullSystem/FullSystem.cpp.o CMakeFiles/dso.dir/src/FullSystem/FullSystemOptimize.cpp.o CMakeFiles/dso.dir/src/FullSystem/FullSystemOptPoint.cpp.o CMakeFiles/dso.dir/src/FullSystem/FullSystemDebugStuff.cpp.o CMakeFiles/dso.dir/src/FullSystem/FullSystemMarginalize.cpp.o CMakeFiles/dso.dir/src/FullSystem/Residuals.cpp.o CMakeFiles/dso.dir/src/FullSystem/CoarseTracker.cpp.o CMakeFiles/dso.dir/src/FullSystem/CoarseInitializer.cpp.o CMakeFiles/dso.dir/src/FullSystem/ImmaturePoint.cpp.o CMakeFiles/dso.dir/src/FullSystem/HessianBlocks.cpp.o CMakeFiles/dso.dir/src/FullSystem/PixelSelector2.cpp.o CMakeFiles/dso.dir/src/OptimizationBackend/EnergyFunctional.cpp.o CMakeFiles/dso.dir/src/OptimizationBackend/AccumulatedTopHessian.cpp.o CMakeFiles/dso.dir/src/OptimizationBackend/AccumulatedSCHessian.cpp.o CMakeFiles/dso.dir/src/OptimizationBackend/EnergyFunctionalStructs.cpp.o CMakeFiles/dso.dir/src/util/settings.cpp.o CMakeFiles/dso.dir/src/util/Undistort.cpp.o CMakeFiles/dso.dir/src/util/globalCalib.cpp.o CMakeFiles/dso.dir/src/IOWrapper/OpenCV/ImageDisplay_OpenCV.cpp.o CMakeFiles/dso.dir/src/IOWrapper/OpenCV/ImageRW_OpenCV.cpp.o CMakeFiles/dso.dir/src/IOWrapper/Pangolin/KeyFrameDisplay.cpp.o CMakeFiles/dso.dir/src/IOWrapper/Pangolin/PangolinDSOViewer.cpp.o CMakeFiles/dso.dir/src/dso_generated_teste.cu.o /usr/local/cuda/lib64/libcudart_static.a -lpthread -ldl -lrt
[ 96%] Building CXX object CMakeFiles/dso_dataset.dir/src/main_dso_pangolin.cpp.o
/usr/bin/c++ -DENABLE_SSE -DHAS_ZIPLIB=1 -I/usr/include/opencv -I/home/cesar/Documents/dso/src -I/home/cesar/Documents/dso/thirdparty/Sophus -I/home/cesar/Documents/dso/thirdparty/sse2neon -I/usr/include/eigen3 -I/home/cesar/Documents/Pangolin/include -I/home/cesar/Documents/Pangolin/build/src/include -I/usr/local/include -I/usr/include/suitesparse -I/usr/local/cuda/include -O3 -g -std=c++11 -D_FORCE_INLINES -o CMakeFiles/dso_dataset.dir/src/main_dso_pangolin.cpp.o -c /home/cesar/Documents/dso/src/main_dso_pangolin.cpp
I also tried to separate .cpp files from .cu files, used add_library for .cpp and cuda_add_library for .cu files, like this:
add_library(dso ${dso_SOURCE_FILES} ${dso_opencv_SOURCE_FILES} ${dso_pangolin_SOURCE_FILES})
cuda_add_library(my_cuda_lib ${PROJECT_SOURCE_DIR}/src/teste.cu)
And then use my_cuda_lib in target_link_libraries, like this:
target_link_libraries(dso_dataset dso boost_system cxsparse ${BOOST_THREAD_LIBRARY} ${LIBZIP_LIBRARY} ${Pangolin_LIBRARIES} ${OpenCV_LIBS} ${CUDA_LIBRARIES} my_cuda_lib)
But still got the same errors.
-- EDIT: MCVE ---
To demonstrate my error i created a simple example. I have 2 simple files, my main which is a .cpp and my cuda file .cu. My main just calls the function on the other file, looks like this:
#include <iostream>
#include "hello_world.cu"
using namespace std;
int main()
{
teste();
return 0;
}
And my .cu file looks like this:
#include <stdio.h>
#include <iostream>
// CUDA runtime
#include </usr/local/cuda-9.0/include/cuda_runtime.h>
// helper functions and utilities to work with CUDA
#include </usr/local/cuda-9.0/samples/common/inc/helper_functions.h>
#include </usr/local/cuda-9.0/samples/common/inc/helper_cuda.h>
__global__ void kernel (void){
extern __shared__ float shared[];
const int tid = threadIdx.x;
const int bid = blockIdx.x;
}
int teste( void ) {
kernel<<<1,1>>>();
printf( "Hello, World!\n" );
return 0;
}
My CMakeLists.txt that i made to compile this looks like this:
cmake_minimum_required(VERSION 2.8)
set(CUDA_HOST_COMPILER /usr/bin/g++-5)
find_package(CUDA QUIET REQUIRED)
# Pass options to NVCC
set(
CUDA_NVCC_FLAGS
${CUDA_NVCC_FLAGS};
-O3
)
# For compilation ...
# Specify target & source files to compile it from
cuda_add_executable(
helloworld
hello_world.cu
teste.cpp
)
After making cmake and running with "cmake --build ." (i don't know why it has to be this command, normally i just do make -j, but in this example only this works) i get the same errors as in my project, ‘threadIdx’ was not declared in this scope, same for 'blockIdx' etc..
Since you are including hello_world.cu file in your main code, then you want to have it compiled with nvcc compiler. To achieve this change name of teste.cpp file to teste.cu (otherwise g++ will be used).
Also remove 'hello_world.cu' from CMakeLists.txt (it is included already in teste file) to have something like this:
cuda_add_executable(
helloworld
teste.cu
)
Then it should work.
-- EDIT: Additional question --
If you want to keep your .cpp file then you need kind of separation between what g++ can do for you and what nvcc should. So you can introduce to your project additional hello_world.h file:
#ifndef HELLO_WORLD_H
#define HELLO_WORLD_H
int teste();
#endif
include it in your teste.cpp:
#include <iostream>
#include "hello_world.h"
using namespace std;
int main()
{
teste();
return 0;
}
and then your CMakeLists.txt looks like in your original example:
...
cuda_add_executable(
helloworld
teste.cpp
hello_world.cu
)
In such a case hello_world.cu will be compiled with nvcc, and then compilling and linking of teste.cpp will be done by g++ (which will be possible in that case since there is no CUDA code in teste.cpp).