Android Studio: Trying to compile a c++ multiple libraries code with interdependencies - c++

This is my code structure:
main executable(CMakeLists.txt)
|
base library(CMakeLists.txt)
profiler library(CMakeLists.txt)
log library(CMakeLists.txt)
Every library is using the base library.
The main is using every library.
Actually this is the CMakeLists.txt of the main executable:
cmake_minimum_required(VERSION 3.4.1)
# build native_app_glue as a static lib
add_library(native_app_glue STATIC
${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wall -fno-exceptions -fno-rtti")
# build the ndk-helper library
set(ndk_helper_dir ../../../../common/ndk_helper)
add_subdirectory(${ndk_helper_dir} ndk_helper)
# build the base library
set(base_dir ../../../../common/base)
add_subdirectory(${base_dir} base)
# build the profile library
set(profile_dir ../../../../common/profile)
add_subdirectory(${profile_dir} profile)
# build the log library
set(log_dir ../../../../common/log)
add_subdirectory(${log_dir} log)
# Export ANativeActivity_onCreate(),

# Refer to: https://github.com/android-ndk/ndk/issues/381.
set(CMAKE_SHARED_LINKER_FLAGS
"${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")
# now build app's shared lib
add_library(MainActivity SHARED
MainActivity.cpp
MainRenderer.cpp)
target_include_directories(MainActivity PRIVATE
${ANDROID_NDK}/sources/android/cpufeatures
${ANDROID_NDK}/sources/android/native_app_glue
${ndk_helper_dir}
${base_dir}
${profile_dir}
${log_dir}
)
# add lib dependencies
target_link_libraries(MainActivity
android
native_app_glue
atomic
EGL
GLESv2
log
ndk-helper
base
profile
log
)
I am unable to add include paths on compile time from any of the libraries to the base library. I am tryint to do it in this way:
On the profile library corresponding CMakeLists.txt
include_directories( ".."
"../.."
"../base/include"
"../../base/include"
"../../../base/include"
"./include"
"include"
)
target_include_directories(profile PRIVATE
${base_dir}
".."
"../.."
"../base/include"
"../../base/include"
"../../../base/include"
"./include"
)
And at compile time I am having an error saying that for example "something.h" which is located on the base library isnt found. If I instead change for "../../base/include/something.h" everything works...
I would like to add those default auto paths for include folders. Is there a way to do it? How can i do it?
I have been struggling through this for long time. Any help is appreciated.

Okay I found the answer...
target_include_directories(profile PRIVATE
${base_dir}
".."
"../.."
"../base/include"
"../../base/include"
"../../../base/include"
"./include"
)
Moving from PRIVATE to PUBLIC did the trick so I am now able to access to the include folders.
Still cant understand the real use of the PRIVATE word, why define an include directory for afterwards not being able to use it? It has no sense...

Related

How can I write a CMakeList.txt file for heavily nested project?

Suppose my source code has the following directory structure:
C:\USERS\PC\SOURCE\REPOS\my_app_src
├───apps {a.hh, b.cc, c.hh, d.cc}
│ └───biosimulations {main1.hh, main1.cc, x.hh, y.cc}
└───core {w.cc, x.hh, y.hh, z.cc}
└───algorithms {p.hh, p.cc, q.hh, r.cc, s.hh, s.cc}
└───trees {r.hh, r.cc, main2.hh, main2.cc}
Each folder has any number of header and source files with any name.
How can I write a CMakeList.txt file for this project?
This is scientific software.
I need to be able to use various parts of the same library to compile and build executables for multiple applications.
For example, in the above sample, main1.exe and main2.exe are supposed to be two different executable files.
Sometimes, I need to be able to switch off one or another executable from compiling.
Do you want the project to support testing, installation, and/or packaging?
No, I don't need them. I just need to be able to compile and execute the apps.
What is in core?
Model classes. e.g., Atom, Protein, Chain, etc.
Are the source files for core part of a single library or executable?
Part of executable. There is no static or dynamic library in the project.
Using add_subdirectory and add_library commands, recursively add all of the source files in the directory structure.
cmake_minimum_required(VERSION 3.x)
project(my_app)
# Add subdirectories recursively
add_subdirectory(apps)
add_subdirectory(core)
add_subdirectory(simulations)
add_subdirectory(ui)
add_subdirectory(utils)
# Create the final executable
add_executable(my_app main.cpp)
# Link the libraries to the executable
target_link_libraries(my_app core simulations apps ui utils)
Then in each subdirectories(apps,core,simulations,ui, utils) you would need to add a new CMakeLists.txt that tells which source files are in that directory and create a library.
cmake_minimum_required(VERSION 3.x)
SET(SRC_FILES
program.cpp
)
#for static libraries
add_library(core STATIC ${SRC_FILES})
#for dynamically linking libraries
add_library(core SHARED ${SRC_FILES})
# If you need executable here
# add_executable(core ${SRC_FILES})
This needs to be repeated for all subdirectories, untill all sources are covered. Above examples gives general structure, you need to define CMAKE flags as required.

Accessing an external project with add-subdirectory results in CMake Error related to export set

I have a project A that depends on spdlog. Here is the structure:
|--- dir A
...|---src
......|---CMakeLists.txt
...|---include
...|---CMakeLists.txt
|---external/3rd_party/spdlog
I am trying to access spdlog in project A by adding a subdirectory. Here is how my A/CMakeLists.txt looks like:
cmake_minimum_required(VERSION 3.9.3 FATAL_ERROR)
project(GLOBAL CXX)
add_subdirectory(../external/3rd_party/spdlog ${CMAKE_BINARY_DIR}/spdlog EXCLUDE_FROM_ALL)
add_subdirectory(src)
Here is how my A/src/CMakeLists.txt looks like:
cmake_minimum_required(VERSION 3.9.3 FATAL_ERROR)
project(Alib CXX)
if(NOT TARGET spdlog)
# Stand-alone build
find_package(spdlog_header_only REQUIRED)
endif()
add_librray(A A.cpp)
target_link_libraries(A PUBLIC spdlog_header_only)
install(TARGETS A
EXPORT ATargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(EXPORT ATargets
NAMESPACE A::
FILE ATargets.cmake
DESTINATION ${INSTALL_CONFIGDIR})
install(FILES AConfig.cmake DESTINATION ${INSTALL_CONFIGDIR})
When I try to build this, I get the following error:
CMake Error: install(EXPORT "ATargets" ...) includes target "A" which requires target "spdlog_header_only" that is not in the export set.
Please can you suggest me how to fix it?
For some reason I need to maintain the same directory structure I have shown above.
Here is a related question but does not have an answer : here
Meaining of the error
Since you use PUBLIC keyword when link your library (A) with spdlog_header_only, CMake expects that this linking is also needed for users of your library. So, when you create config file for your library (with install(EXPORT)), CMake adds linking with spdlog_header_only target into the config file too. Like
# [ATargets.cmake]
target_link_libraries(A::A PUBLIC spdlog_header_only)
Linking with a target implies existence of this target, but you do not install spdlog_header_only target. Because of that, created config file for your library won't work. This is what CMake tells you in the error message.
Simple fix
The simplest fix would be using PRIVATE linking with spdlog_header_only target, so that linking won't be part of the config file. Beware, in that case a user of your (installed) library won't get access to the header files for spdlog.
(But a user could obtain these headers by other means.)
Hard fix
But if you want a user of your library to have access to spdlog headers (or, worse, the public headers of your library use #include for headers from spdlog), then you cannot drop PUBLIC linking. In that case you need to install spdlog_header_only target too. E.g. by enabling SPDLOG_INSTALL option
set(SPDLOG_INSTALL ON)
before
add_subdirectory(../external/3rd_party/spdlog ${CMAKE_BINARY_DIR}/spdlog EXCLUDE_FROM_ALL)
(Note, that aside from enabling SPDLOG_INSTALL option, several other adjustments needs to be done for make the config file for your library to work.)

Cannot link local libraries in CMake

I'm developing a c++ program on visual studio that will be deployed on linux, and it is debugged on linux through an ssh. Currently, this is the structure of my folder:
ANT
-xscommon
--xscommon_config.h
-xscontroller
-xstypes
ANT.cpp
ANT.h
CMakeLists.txt
CMakeSettings.json
hashes.h
quaternionic.h
stars.h
Currently, all the .h, .cpp, .o, .cpp.o, .a files that I think I have to link to are kept within the three xs------- directories. I am quite new to cmake, and this linking to these libraries is giving me trouble; I am able to link correctly to the includes, but there are undefined references errors thrown when I don't do linking, and when I attempt linking, it throws errors. This is my current CMakeLists.txt file:
# CMakeList.txt : CMake project for ANT, include source and define
# project specific logic h"ere.
#
cmake_minimum_required (VERSION 3.8)
project ("ANT")
link_directories(${ANT_SOURCE_DIR}/xscommon xscontroller xstypes)
add_executable(
ANT
"ANT.cpp"
"ANT.h"
"quaternionic.h"
"stars.h"
"hashes.h"
)
target_include_directories(ANT PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(ANT PUBLIC xscommon_config)
When I run this, the builder says the following:
/usr/bin/ld: cannot find -lxscommon_config
I need to look for these libraries in the directory that ANT.cpp is in, as this is where they are kept, however nothing I do (and I have messed around with configurations for hours now) will tell camke to look for these libraries in the src folder. it always goes to /usr/bin/ld.
I really just need to know what to tell CMake such that it will look in the correct place for each file, that is if I am telling it to look for the correct file (I am fairly sure I am).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Update
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
So I have remade the CMakeLists.txt file to this:
# CMakeList.txt : CMake project for ANT, include source and define
# project specific logic here.
#
cmake_minimum_required (VERSION 3.15)
project ("ANT")
#[STATIC | SHARED | MODULE]
#[STATIC | SHARED | MODULE]
#[STATIC | SHARED | MODULE]
add_library(xscommon SHARED IMPORTED)
add_library(xscontroller SHARED IMPORTED)
add_library(xstypes SHARED IMPORTED)
add_executable(
ANT
"ANT.cpp"
"ANT.h"
)
target_include_directories(ANT PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
And still get undefined references. I am going to try building the libraries instead. Additionally, I have contacted the manufacturer of the IMUs which use this SDK, as colleagues have not been able to fix this either.
The problem is you are linking to a library that has not been build.
This
# link to this directory
target_link_libraries(ANT PRIVATE xscommon)
tries to link to a library called xscommon to the target ANT but you have not build xscommon anywhere in your project.
If xscommon is a pre-build library and you just want to import it then add the library and set the IMPORTED target property:
add_library(xscommon [STATIC | SHARED | MODULE] IMPORTED)
If you want to build xscommon in your root CMakeLists.txt. Add xscommon as a library and include the location of the headers.
add_library(xscommon [STATIC | SHARED | MODULE]
xxx/xxx.cpp #list all source files that build the library - use relative path
)
target_include_directories(xscommon PRIVATE
xxx/xxx #path to the location of library header files
)
Also you don't need to add the header files when adding the executable. So this
add_executable(
ANT
"ANT.cpp"
"ANT.h"
"quaternionic.h"
"stars.h"
"hashes.h"
)
can be simplified to
add_executable(
ANT
"ANT.cpp"
)
Suppose your dir is like this:
ANT
-xscommon
--xscommon_config.h
--xscommon_config.cpp
...
First add a CMakeLists.txt file to xscommon/:
ANT
-xscommon
--CMakeLists.txt
--xscommon_config.h
--xscommon_config.cpp
...
Now in xscommon/CMakeLists.txt we will create a library, that will be imported and linked in the main CMakeLists.txt file:
xscommon/CMakeLists.txt:
#define another target, let's name it 'xscommon'
add_library(xscommon
xscommon_config.h
xscommon_config.cpp
#more sources if you want
)
Now in the main CMakeLists.txt file:
cmake_minimum_required (VERSION 3.8)
project ("ANT")
#remove this line
#link_directories(${ANT_SOURCE_DIR}/xscommon xscontroller xstypes)
add_executable(
ANT
"ANT.cpp"
"ANT.h"
"quaternionic.h"
"stars.h"
"hashes.h"
)
# add the xscommon directory, this will make the library target defined there available here
add_subdirectory(xscommon)
# link to this directory
target_link_libraries(ANT PRIVATE xscommon)
# use PUBLIC if the xscommon library will be part of the public interface of your
# library. But since it is an executable, PRIVATE is better here.
target_include_directories(ANT PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
Use the above method, you can create more libraries and link to them.
Note that it is not necessary to create separate cmake files for each subdirectory but it is considered a good practice and modularizes your code. If you want to do this in the main cmake file instead of creating a subdirectory, add this to the main cmake:
add_library(xscommon
xscommon/xscommon_config.h
xscommon/xscommon_config.cpp
#more sources if you want
)
Update according to the changes in question
Your current CMakeLists.txt:
These three lines below are not doing anything, definitely not what you think. add_library() command has the word "add" in it, I know, but it doesn't add any library, just like add_executable doesn't add any executable. It creates a library.
add_library(xscommon SHARED IMPORTED)
add_library(xscontroller SHARED IMPORTED)
add_library(xstypes SHARED IMPORTED)
How to create a library in cmake out of two file a.cpp and a.h:
add_library(myALib "a.cpp")
That's it. If you have more sources, you will include them accordingly of course. In your case you will have to add the sources of xscommon and others accordingly.
Once you have created the libraries, you need to link them to your executable. If you won't you will get undefined reference errors because compiler can locate the declarations in header files but not the definitions of your code which exists in .cpp files.
So, how do you link? Simple:
target_link_libraries(TARGET_NAME PUBLIC | PRIVATE LIBRARY_NAME)
# TARGET_NAME: can be `executable` or `library`
# PUBLIC or PRIVATE (for exe, it is usually private)
# LIBRARY_NAME: Name of library you want to link to TARGET_NAME
# So if you wanted to link "myALib" which I created above to ANT, you would do:
target_link_libraries(ANT PRIVATE myALib)
# Note: You need to add this line **after** add_executable() because target "ANT" will be created after that. You can do the linking after the "target_include_directories" command.

CMake - objects being built twice unnecessarily?

I have a list of files that need to be compiled for my main executable. My tests also need these files. When the test executable(s) are built, the object files are built again, even though earlier in the build they were built when the main executable was built.
Am I wrong in thinking this is not needed? If so is there a way to disable this?
Example:
set(SOURCES
${SOURCE_DIR}/file.c
${SOURCE_DIR}/another_file.c)
set(MAIN ${SOURCE_DIR}/main.c)
add_executable(main_executable ${SOURCES} ${MAIN})
add_executable(test1_ex ${PROJECT_SOURCE_DIR}/test/test1.cc ${SOURCES})
Put the common code in a library and link the library to both your application and tests.
# The application's sources - except main
set(SOURCES
${SOURCE_DIR}/file.c
${SOURCE_DIR}/another_file.c)
# build an application library
add_library(app_lib ${SOURCES})
# build an executable in terms of the application library
set(MAIN ${SOURCE_DIR}/main.c)
add_executable(main_executable ${MAIN})
target_link_libraries(main_executable PRIVATE app_lib)
# build a test executable in terms of the application library
add_executable(test1_ex ${PROJECT_SOURCE_DIR}/test/test1.cc)
target_link_libraries(test1_ex PRIVATE app_lib)
This could be due to the following scenario:
add_library(mylib1 file1.cpp common.cpp)
add_library(mylib2 file2.cpp common.cpp)
That created the same problem you're having for me, where common.cpp was being rebuilt for every library. My solution was this:
add_library(common_lib common.cpp)
add_library(mylib1 file1.cpp)
add_library(mylib2 file2.cpp)
target_link_libraries(mylib1 common_lib)
target_link_libraries(mylib2 common_lib)
That resolved the problem for me as the building (object creation) was done once, but it was linked to every other library.

How to work around CMake + XCode 4 paths dependencies?

I have projects structured like so:
Libs/
Apps1/
Apps2/
In each folder is a CMakeLists.txt. I would like to generate a project file for each of the folders, and each AppsN references Libs. My method of doing that is by calling CMake's add_subdirectory(../Libs/Source/LibN) etc.
Now when I do this, CMake says add_subdirectory must specify a unique absolute path for the binary output folder.
See this post:
Xcode dependencies across different build directories?
XCode can not handle dependencies when the build output folder is unique per target. It needs one folder. And CMake does this by default, it just refuses to when the folder is not a subdir.
I tried altering and changing the output path after the target is created. This will build the objects to the output folder, XCode sees them, but all references to this target in the CMake script will use the unique path.
Proposed solutions are:
include project files in App1/Projects/Subdir and duplicate projects in an irrelevant location
reorganize my folders to a shared parent folder to avoid this CMake craziness, which presents some security problems for me (as some dirs are not public)
never refer to the target by its CMake name, instead using the shared path name. Not sure how to do this properly
try and get this patched on the CMake side somehow
switch to premake
Try to add the following to the root CMakeLists.txt:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0)
PROJECT (ContainerProject)
SET (LIBRARY_OUTPUT_PATH ${ContainerProject_BINARY_DIR}/bin CACHE PATH
"Single output directory for building all libraries.")
SET (EXECUTABLE_OUTPUT_PATH ${ContainerProject_BINARY_DIR}/bin CACHE PATH
"Single output directory for building all executables.")
MARK_AS_ADVANCED(LIBRARY_OUTPUT_PATH EXECUTABLE_OUTPUT_PATH)
# for common headers (all project could include them, off topic)
INCLUDE_DIRECTORIES(ContainerProject_SOURCE_DIR/include)
# for add_subdirectory:
# 1) do not use relative paths (just as an addition to absolute path),
# 2) include your stuffs in build order, so your path structure should
# depend on build order,
# 3) you could use all variables what are already loaded in previous
# add_subdirectory commands.
#
# - inside here you should make CMakeLists.txt for all libs and for the
# container folders, too.
add_subdirectory(Libs)
# you could use Libs inside Apps, because they have been in this point of
# the script
add_subdirectory(Apps1)
add_subdirectory(Apps2)
In Libs CMakeLists.txt:
add_subdirectory(Source)
In Source CMakeLists.txt:
add_subdirectory(Lib1)
# Lib2 could depend on Lib1
add_subdirectory(Lib2)
In this way all Apps could use all libraries. All binary will be made to your binary ${root}/bin.
An example lib:
PROJECT(ExampleLib)
INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
)
SET(ExampleLibSrcs
...
)
ADD_LIBRARY(ExampleLib SHARED ${ExampleLibSrcs})
An example executable (with dependency):
PROJECT(ExampleBin)
INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${ExampleLib_SOURCE_DIR}
)
SET(ExampleBinSrcs
...
)
# OSX gui style executable (Finder could use it)
ADD_EXECUTABLE(ExampleBin MACOSX_BUNDLE ${ExampleBinSrcs})
TARGET_LINK_LIBRARIES(ExampleBin
ExampleLib
)
Here is a stupid and working example.