How to link many files with cmake - c++

How Is simple way to link files in this tree files with cmake?
root
├── 1
│ └── 2
│ └── 3
├── 2
│ └── 3
└── 3
└── 4
└── 5
└── 6
└── 7
How can I better than this example?
file(GLOB SOURCES "*.cpp" "*/*.cpp" "*/*/*.cpp" "*/*/*/*.cpp" "*/*/*/*/*.cpp")
add_executable(a.out ${SOURCES})

Related

CMake linking error (collect2: ld returned 1 exit status) /usr/bin/ld: cannot find -lexpression

The project structure is as below
├── ast
│   ├── CMakeLists.txt
│   ├── expression
│   │   ├── CMakeLists.txt
│   │   ├── Expression.cpp
│   │   ├── Expression.hpp
│   │   ├── NumericExpression.cpp
│   │   └── NumericExpression.h
│   ├── Visitor.cpp
│   └── Visitor.hpp
├── callSlang
│   ├── CMakeLists.txt
│   └── main.cpp
├── CMakeLists.txt
├── contexts
│   ├── CMakeLists.txt
│   ├── Context.hpp
│   ├── Symbol.cpp
│   ├── Symbol.hpp
│   └── SymbolTable.hpp
├── frontend
│   ├── CMakeLists.txt
│   ├── Parser.cpp
│   └── Parser.hpp
├── Makefile
├── meta
│   ├── CMakeLists.txt
│   └── Meta.hpp
└── README.md
CMakeLists.txt
cmake_minimum_required(VERSION 3.16.3)
# set the project name
# https://stackoverflow.com/questions/71740678/cmake-error-in-findterminfo-with-clang-15-on-macos
project(slangLLvm VERSION 1.0 LANGUAGES C CXX)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_BUILD_TYPE "Debug")
set(LLVM_DIR /usr/lib/llvm-14/lib/cmake/llvm)
find_package(LLVM REQUIRED CONFIG
PATHS ${search_paths}
NO_DEFAULT_PATH)
add_subdirectory(meta)
add_subdirectory(contexts)
add_subdirectory(ast)
add_subdirectory(frontend)
add_subdirectory(callSlang)
callSlang/CMakeLists.txt
set(SOURCE_FILE main.cpp)
# add the files for creating executable
add_executable(slangLLVM ${SOURCE_FILE})
#link the libs
target_link_libraries(slangLLVM
PRIVATE
ast
frontend
)
ast/CMakeLists.txt
set(SOURCE_FILES Visitor.cpp)
add_library(ast ${SOURCE_FILES})
target_link_libraries(ast
PUBLIC
meta
contexts
LLVMSupport
expression
PRIVATE
frontend
)
# get the include dirs
target_include_directories(ast
INTERFACE
.
PUBLIC
${LLVM_INCLUDE_DIRS}
${PROJECT_SOURCE_DIR}/meta
${PROJECT_SOURCE_DIR}/ast/expression
)
add_subdirectory(expression)
expression/CMakeLists.txt
set(SOURCE_FILES Expression.cpp NumericExpression.cpp)
add_library(experssion ${SOURCE_FILES})
target_link_libraries(experssion
PUBLIC
ast
)
# get the include dirs
target_include_directories(experssion
INTERFACE
.
PUBLIC
${LLVM_INCLUDE_DIRS}
${PROJECT_SOURCE_DIR}/contexts
${PROJECT_SOURCE_DIR}/ast
${PROJECT_SOURCE_DIR}/meta
)
# INTERFACE tells to use includes to other libs but on the ast
frontend/CMakeLists.txt
set(SOURCE_FILES Parser.cpp)
add_library(frontend STATIC ${SOURCE_FILES})
target_link_libraries(frontend
PRIVATE
ast
)
# get the include dirs
target_include_directories(frontend
INTERFACE
.
PRIVATE
${PROJECT_BINARY_DIR}
${PROJECT_SOURCE_DIR}/ast
${PROJECT_SOURCE_DIR}/contexts
${PROJECT_SOURCE_DIR}/ast/expression
)
meta/CMakeLists.txt
add_library(meta INTERFACE)
# get the include dirs
target_include_directories(meta INTERFACE .)
This compiles without error but fails during linking with the following error
[100%] Linking CXX executable slangLLVM
/usr/bin/ld: cannot find -lexpression
collect2: error: ld returned 1 exit status
make[3]: *** [callSlang/CMakeFiles/slangLLVM.dir/build.make:93: callSlang/slangLLVM] Error 1
make[3]: Leaving directory '/home/nithin/learn/c-cpp/slang-llvm/build'
make[2]: *** [CMakeFiles/Makefile2:392: callSlang/CMakeFiles/slangLLVM.dir/all] Error 2
make[2]: Leaving directory '/home/nithin/learn/c-cpp/slang-llvm/build'
make[1]: *** [Makefile:84: all] Error 2
make[1]: Leaving directory '/home/nithin/learn/c-cpp/slang-llvm/build'
make: *** [Makefile:4: all] Error 2
CallSlang depends on ast, ast depends on the expression and vice versa.
I have tried the solution in the link but it not-working so far for me. I am really new to CMake. Is it caused by the circular call by ast and expression, if so how can correct the same?
The complete code can be found in this link
Could someone please tell me the possible cause and solution? If I've missed out anything, over- or under-emphasized a specific point, please let me know in the comments. Thank you so much in advance for your time.

C recursive makefile targets for different build types

I am new to Makefiles and have been trying to get following working with little success. In my project each subdir has:
Release/ dir with a makefile that builds object files into ./Release/Src/ and outputs a dir.so to ../Bin/ (1 for each dir)
Debug/ dir with a makefile that build object files into ./Debug/Src/ and outputs a dir.so to ../Bin/ (1 for each dir)
Src/ dir with source code from which Release or Debug is built
Currently the below Makefile seems to always builds Release/ and not Debug/. I would like a way (or some equivalent) to run something like:
make release - which would recursively run make in the release folders OR
make debug - which would recursively run make in the debug folders
I would like to retain the recursive nature of the makefiles if possible here (I appreciate there is some dispute as to whether this is best practice).
Project structure:
├── Makefile
├── Bin
│ ├── *.so
├── dir1
│ ├── Src
│ │ ├── prog1.cpp
│ │ ├── prog2.cpp
│ ├── Debug
│ │ ├── makefile
│ │ ├── Src
│ │ | ├── *.o
| | | ├── *.d
│ ├── Release
│ │ ├── makefile
│ │ ├── Src
│ │ | ├── *.o
| | | ├── *.d
├── dir2
│ ├── Src
│ │ ├── prog1.cpp
│ │ ├── prog2.cpp
│ ├── Debug
│ │ ├── makefile
│ │ ├── Src
│ │ | ├── *.o
| | | ├── *.d
│ ├── Release
│ │ ├── makefile
│ │ ├── Src
│ │ | ├── *.o
| | | ├── *.d
Top level Makefile:
SUBDIRS := dir1 dir2 dir3 #...
DEBUG_DIRS := $(addsuffix /Debug,$(SUBDIRS))
RELEASE_DIRS := $(addsuffix /Release,$(SUBDIRS))
$(info $(RELEASE_DIRS))
.PHONY: debug release $(DEBUG_DIRS) $(RELEASE_DIRS) $(SUBDIRS)
debug: $(DEBUG_DIRS)
$(DEBUG_DIRS):
$(MAKE) -C $#
release: $(RELEASE_DIRS)
$(RELEASE_DIRS):
$(MAKE) -C $#
If you're compiling with different options, then what you need to do...
Produce different .so files such as Dir-debug.so and Dir-release.so.
Based on .o files found in different directories such as obj-debug/foo.o and obj-release/foo.o
Then you can create generic, nearly identical rules for building both obj-debug/%.o and obj-release/%.o
And after that, nearly identical rules for creating the shared libs.
Using GNU make patsubst() method (substitute) means you can fairly readily do something like this:
ALL_MY_SRC = $(shell find ${SRCDIR} -name "*.cpp" | sort)
DEBUG_OBJ = $patsubst(%.cpp, ${DEBUG_OBJDIR}/%.o, ${ALL_MY_SRC})
RELEASE_OBJ = $patsubst(%.cpp, ${RELEASE_OBJDIR}/%.o, ${ALL_MY_SRC})
Those might not be perfect. You might have to play with them a bit. But that should give you one variable with all the source and 1 each for the two sets of object lists. Then you can make a rule like:
${DEBUG_OBJDIR}/%.o: ${SRCDIR}/%.cpp
g++ ...
Again, play with it.

cmake target_link_libraries() cannot find renamed lib target by set_target_properties(archive_output_name)

RT~ ps: cmake version 3.9.2
My codebase just like this.
suzanwen#n224-004-133:~/repos/C++/ttt:)$ tree -L 2
.
├── build
│   ├── bin
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   ├── lib
│   ├── Makefile
│   ├── test
│   └── thirdparty
├── build.sh
├── CMakeLists.txt
├── Makefile
├── test
│   ├── CMakeLists.txt
│   └── main.cc
└── thirdparty
├── CMakeLists.txt
├── gflags
└── hellolib
10 directories, 9 files
my thirdparty/hellolib/CMakeLists.txt is
PROJECT(hello)
SET(LIBHELLO_SRC hello.cc)
MESSAGE(STATUS "LIBRARY PATH=" ${LIBRARY_OUTPUT_PATH})
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES(hello_static PROPERTIES ARCHIVE_OUTPUT_NAME "hello")
my test/CMakeLists.txt is
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/thirdparty/hellolib
${PROJECT_SOURCE_DIR}/thirdparty/gflags/include)
IF(LIBRARY_OUTPUT_PATH)
LINK_DIRECTORIES(${LIBRARY_OUTPUT_PATH})
ENDIF(LIBRARY_OUTPUT_PATH)
ADD_EXECUTABLE(main main.cc)
TARGET_LINK_LIBRARIES(main hello)
# TARGET_LINK_LIBRARIES(main hello_static)
when I build my top-level project, an error occurs like this.
/usr/bin/c++ -rdynamic CMakeFiles/main.dir/main.cc.o -o ../bin/main -L/home/suzanwen/repos/C++/ttt/build/lib -Wl,-rpath,/home/suzanwen/repos/C++/ttt/build/lib -lhello
/usr/bin/ld: cannot find -lhello
But when I comment the line # SET_TARGET_PROPERTIES(hello_static PROPERTIES ARCHIVE_OUTPUT_NAME "hello") and TARGET_LINK_LIBRARIES with hello_static, everything goes fine.
It seems that TARGET_LINK_LIBRARIES cannot find renamed lib target. Could anyone explain it? thanks in advance.
It seems that TARGET_LINK_LIBRARIES cannot find renamed lib target.
Setting ARCHIVE_OUTPUT_NAME property renames not a target, but an output file. So linking with a target still works:
TARGET_LINK_LIBRARIES(main hello_static)
One cannot rename the target once it is created, but it is possible to create ALIAS for a target:
ADD_LIBRARY(hello ALIAS hello_static)
After that it is possible to link with the alias:
TARGET_LINK_LIBRARIES(main hello)

Compile and link OpenCV to my project in my main CMakeLists.txt

I am new to cmake. I have a project which uses dlib and opencv. They are defined as submodules which are in third_party folder. I want to link them to my main project which is 'node' with cmake but I could not achieved. I am sharing my project tree. I did with find_package(OpenCV) and target_link_libraries(recognition-node ${OPENCV_LIBS}) way but I need to compile from source without installing anything. At last, I just want to write 'cmake . && make'
.
├── CMakeLists.txt
├── node
│ ├── build.sh
│ ├── CMakeLists.txt
│ ├── configure.sh
│ ├── findfacestask.cpp
│ ├── findfacestask.h
│ ├── main.cpp
│ ├── matrixwrapper.h
│ ├── poolcontext.cpp
│ ├── poolcontext.h
│ ├── recognition.dat
│ ├── recognizefacetask.cpp
│ ├── recognizefacetask.h
│ ├── runscript
│ ├── sp.dat
│ ├── task.cpp
│ ├── task.h
│ ├── unhandledexception.cpp
│ ├── unhandledexception.h
│ ├── webcamfeed.cpp
│ ├── webcamfeed.h
│ ├── wrapper.cpp
│ └── wrapper.h
└── third_party
├── dlib
│ ├── appveyor.yml
│ ├── CMakeLists.txt
│ ├── dlib
│ ├── docs
│ ├── examples
│ ├── MANIFEST.in
│ ├── python_examples
│ ├── README.md
│ ├── setup.py
│ └── tools
└── opencv
├── 3rdparty
├── apps
├── cmake
├── CMakeLists.txt
├── CONTRIBUTING.md
├── data
├── doc
├── include
├── LICENSE
├── modules
├── platforms
├── README.md
└── samples
Content of my top CMakeLists.txt
cmake_minimum_required(VERSION 2.8.12)
set (CMAKE_CXX_STANDARD 11)
add_subdirectory(node)
add_subdirectory(third_party/dlib)
add_subdirectory(third_party/opencv)
Content of node/CMakeLists.txt
cmake_minimum_required(VERSION 2.8.12)
project(recognition-node)
set(CMAKE_AUTOMOC ON)
find_package(Qt5Widgets REQUIRED)
add_executable(recognition-node main.cpp
webcamfeed.cpp
poolcontext.cpp
unhandledexception.cpp
task.cpp
findfacestask.cpp
wrapper.cpp
recognizefacetask.cpp)
target_link_libraries(recognition-node Qt5::Widgets)
target_link_libraries(recognition-node dlib::dlib)
target_link_libraries(recognition-node opencv::core)
It gives error in 'make' stage which is :
/home/arnes/workspace/recognition-node/node/poolcontext.h:10:28: fatal error:
opencv2/core.hpp: No such file or directory
Since you insist on keeping the opencv in your project tree
It is easier way but I just want it to do in this way.
Here is the solution that for sure works fine with your project tree that you posted in the question and with opencv-3.4.1. For simplicity I will neglect dlib library and Qt dependency, since you didn't have any problem with it.
Root CMakeLists.txt should have the following content:
cmake_minimum_required(VERSION 2.8.11) # or anything higher, if you wish
project(recognition-node CXX)
add_subdirectory(node)
The CMakeLists.txt under the node directory should have the following content:
add_subdirectory(third_party)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g") # or any other additional flags
# at this point you can add find_package(Qt5Widgets REQUIRED) and later link your binary against Qt5::widgets as well
add_executable(myExec main.cpp
# and put here all the other source files of your project ...
)
# for linking libs I have put additionally highgui and imgproc to check the solution against OpenCV official sample
target_link_libraries(myExec opencv_core opencv_highgui opencv_imgproc)
target_include_directories(myExec PUBLIC
third_party/opencv/modules/calib3d/include
third_party/opencv/modules/core/include
third_party/opencv/modules/cudaarithm/include
third_party/opencv/modules/cudabgsegm/include
third_party/opencv/modules/cudacodec/include
third_party/opencv/modules/cudafeatures2d/include
third_party/opencv/modules/cudafilters/include
third_party/opencv/modules/cudaimgproc/include
third_party/opencv/modules/cudalegacy/include
third_party/opencv/modules/cudaobjdetect/include
third_party/opencv/modules/cudaoptflow/include
third_party/opencv/modules/cudastereo/include
third_party/opencv/modules/cudawarping/include
third_party/opencv/modules/cudev/include
third_party/opencv/modules/dnn/include
third_party/opencv/modules/features2d/include
third_party/opencv/modules/flann/include
third_party/opencv/modules/highgui/include
third_party/opencv/modules/imgcodecs/include
third_party/opencv/modules/imgproc/include
third_party/opencv/modules/ml/include
third_party/opencv/modules/objdetect/include
third_party/opencv/modules/photo/include
third_party/opencv/modules/shape/include
third_party/opencv/modules/stitching/include
third_party/opencv/modules/superres/include
third_party/opencv/modules/ts/include
third_party/opencv/modules/video/include
third_party/opencv/modules/videoio/include
third_party/opencv/modules/videostab/include
third_party/opencv/modules/viz/include
third_party/opencv/modules/world/include
)
The CMakeLists.txt under third_party should contain only:
add_subdirectory(opencv)
# add_subdirectory(dlib) # if you will use dlib, of course also add dlib
The sample I used to verify the build is contours2.cpp (just copy pasted the content into main.cpp).
However, I still think that it is a terrible idea to use this solution.
OpenCv takes really a lot of time to compile
you have to manually add include dirs (you can use some macro generators, but usually it looks even more ugly)
in your build system you have a lot of targets (over 300) that you don't really need, including install target
So, my recommendation is: if you want, use this solution for scientific purpose, but just compile and install OpenCv system-wise (or locally, if you are not the admin) when you really need to use it.

Unit testing with QTestLib

I'm trying to unit-testing my Qt application with QTestLib. I saw that the new Visual Studio 2012 has a built-in C++ test framework and googling for it I saw this page that talks about different methods to test a native project. I would have two different projects, one for the normal program and one for the tests. Actually my application is not a DLL but it's a simple C++ exe. Is the best way to test it with another project to link against .obj files or against libs? I wouldn't export anything from the source code as mine is not a DLL
This is a typical QtTest project with three code units: unit1, unit2 and unit3
project/
├── project.pro
├── src
│ ├── main.cpp
│ ├── src.pro
│ ├── unit1.cpp
│ ├── unit1.h
│ ├── unit2.cpp
│ ├── unit2.h
│ ├── unit3.cpp
│ └── unit3.h
└── tests
├── stubs
│ ├── stubs.pro
│ ├── unit1_stub.cpp
│ ├── unit2_stub.cpp
│ └── unit3_stub.cpp
├── test1
│ ├── test1.cpp
│ ├── test1.h
│ └── test1.pro
├── test2
│ ├── test2.cpp
│ ├── test2.h
│ └── test2.pro
├── test3
│ ├── test3.cpp
│ ├── test3.h
│ └── test3.pro
└── tests.pro
This project results in 4 binaries: 1 application itself and three test binaries for testing each of the units. For example, test1 should include src/unit1.cpp, src/unit1.h and also stubbed unit2 and unit3: src/unit2.h, tests/stubs/unit2_stub.cpp, src/unit2.h, tests/stubs/unit3_stub.cpp. With this kind of setup src/unit1.cpp and tests/stubs/unit1_tests.cpp will be compiled twice and this number will grow, if number of units will be larger. This is not a problem for small projects, but for huge projects this may lead to significant increase of build time.
Then splitting unitX.cpp and unitX.h into separate libraries with static linking to main application and each of the tests will eliminate need for building multiple times.