Let's say I have to distribute a C++ library libA which depends on other libraries libB and libC.
The final user will have to include just the header files of libA but needs to link also the others two.
What's the preferable way to distribute all together the libraries?
Is it possible to use cpack to take care of it?
If you have to hide the source code, then you could precompile the libraries yourselves and just distribute the static .a files and the header files seperately for each distribution.
However, If you want the code to be transparent to the end users and let the users compile the libraries on their own. Then you could try cmake.
The common folder structure for a library will look like this
MainFolder
src ( To have all the required Src files )
include ( all the necessary files to be included )
test ( to run test cases upon installation to validate a successfull installation -- optional )
Then you could create a CMakeLists.txt file in the root folder which would look like this,
cmake_minimum_required(VERSION 3.2)
project(MyAwesomeLibrary)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")// Sets up the compiler and flags
include_directories("${CMAKE_SOURCE_DIR}/include") // This includes the .h files in include directory
// Set the Codes to be compiled for Different Libraries
set (LIB_A ${CMAKE_SOURCE_DIR}/lib_a.c);
set (LIB_B ${CMAKE_SOURCE_DIR}/lib_b.c);
set (LIB_C ${CMAKE_SOURCE_DIR}/lib_c.c);
add_library(MyAwesomeStaticLib STATIC ${LIB_A} ${LIB_B} ${LIB_C}) // Generates the static library
If you have multiple files to be compiled for each of the libraries then you can refer this link.
how would I compile multiple files in a folder?
Then the end user can use the library by linking the generated MyAwesomeStaticLib.a file and also use the -I flag to include the include directories.
Related
I have two folders with two different libraries.
LibBase
LibPublic
LibB includes some LibBase's headers.
I'd like to have LibPublic as a static library including "LibBase" in its .a file.
Each CMakeLists.txt is:
set(SRCLIB file.cpp)
add_library(${PROJECT_NAME} ${SRCLIB})
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
target_include_directories(...)
The top level CMakeLists.txt:
add_subdirectory(LibBase)
add_subdirectory(LibPublic)
How can I force CMake to include LibBase inside LibPublic so that I can only share libLibPublic.a?
LibBase is a proprietary library and LibPublic is the "public" library we share.
LibBase and LibPublic, both may be added using add_subdirectory() by other libraries or apps so that a single app executable or a single .a file can be provided. Each "library" should be compiled as just objects, static library or even dynamic library. I'd like them to be generic, and an upper CMakeLists.txt will decide what to do.
I tried with add_library(${PROJECT_NAME}-obj OBJECT ${SRCLIB}) but I get errors:
CMakeLists.txt:22 (target_include_directories):
Cannot specify include directories for target "LibPublic" which is not
built by this project.
Given the following file and some dummy cpp files:
cmake_minimum_required(VERSION 3.10)
project(foo)
add_library(Base STATIC base.cpp)
add_library(Public STATIC public.cpp)
target_sources(Public PRIVATE $<TARGET_OBJECTS:Base>)
I end up with a libPublic.a that contains functions from both libraries.
Note that this is a solution to your question, but maybe not a solution to your underlying requirement: static libraries are simple collections of functions and the functions in "Base" are plainly visible.
If I have this source tree:
C:\app:
src:
CMakeLists.txt
main.cpp --> #include "acme/header_only_lib/api.h"
D:\3rdparty\acme\header_only_lib:
api.h --> #include "detail.h"
detail.h
Without using symlink tricks, and without adding files to the 3rdparty folders, if I must retain #include "acme/header_only_lib/api.h" in main.cpp, how should I specify the include directories in CMake such that api.h can see detail.h, without adding global include directory of D:\3rdparty\acme\header_only_lib? The header-only-lib is not an executable nor library target, and its code is not modifiable by me. I also don't want to pollute my global include directories by adding D:\3rdparty\acme\header_only_lib because the filenames inside there are too common and will easily clash with other libraries/future code.
Is there a CMake mechanism where I can say:
Only for D:\3rdparty\acme\header_only_lib\api.h, add D:\3rdparty\acme\header_only_lib as the include directory?
To add a directory to the global list of include directories, you use e.g.
include_directories( ${CMAKE_SOURCE_DIR}/3rdparty )
Note that you should not hardcode absolute paths (like D:\) into your CMakeLists.txt as that makes it impossible to build your project in any other location. CMake offers variables like ${CMAKE_SOURCE_DIR} and ${CMAKE_BINARY_DIR} for just that purpose.
If you want to add a directory to the list of include directories for a specific part of your build only, you use e.g.
target_include_directories( app PRIVATE ${CMAKE_SOURCE_DIR}/3rdparty )
This adds the directory only for the target (executable / library) app.
Note that, if your acme/header_only_lib is supposed to be installed alongside with the app binaries, this approach won't work, as your acme headers would need to "see" each other on the client's machine, which is unlikely if they reside in the acme/header_only_lib subdirectory but address each other without subdirs. That would require your client (who isn't using your CMakeLists.txt for his builds) to add acme/header_only_lib to the include paths for your header lib to work -- you should not do that.
Use include_directories or target_include_directories:
include_directories("D:\3rdparty")
OR with target_include_directories if you want to make this change only for the main target:
add_executable(main main.cpp)
target_include_directories(main PUBLIC "D:\3rdparty")
Then you can just #include "acme/header_only_lib/api.h" or #include <acme/header_only_lib/api.h>
Header only lib
If you want to do this for header-only-lib only, you need to do this in it's CMake file. First add the library as INTERFACE with no source files:
add_library(header-only INTERFACE)
Then include directories for it:
target_include_directories(header-only INTERFACE include-dir-for-header-only)
Then link it to the main target
find_library(HeaderOnly
NAMES header-only
HINTS "D:\3rdparty\path-to-lib"
)
target_link_libraries(main header-only)
I am trying to make a native C++ code in Android Studio and with CMake. My C++ code uses precompiled static library (.a file).
I included its header .h in my C++ code. I also linked the location of the .h and the .a files in my CMakeList.txt as below:
include_directories(".h file location")
Then:
add_library(lib_fastcv STATIC IMPORTED)
set_target_properties(lib_fastcv PROPERTIES IMPORTED_LOCATION
".a file location")
And at the end:
target_link_libraries (...lib_fastcv....)
However, as soon as I use any function from the .a static library it complains that it cannot recognize the function which means the static library is not linked correctly to my C++ code.
Does anyone know what else I need to do?
Should I also edit my build.gradle to include information about the library file?
this is my solution:
So, first of all, CMake can be weird to use at the beginning.
1- native-lib1 is the output product of CMake. Later java will only see .so of this
add_library( # This is out .so product (libnative-lib1.so)
native-lib1
# Sets the library as a shared library.
SHARED
# These are the input .cpp source files
native-lib.cpp
SRC2.cpp
Any other cpp/c source file you want to compile
)
2- Any library that you included in your souse file, its .h needs to be addressed here:
target_include_directories(# This is out .so product (libnative-lib1.so)
native-lib1 PRIVATE
${CMAKE_SOURCE_DIR}/include)
3- Any actual library you used, its atual .a or .cpp should be addrressed to CMake this way:
target_link_libraries(
# This is out .so product (libnative-lib1.so)
native-lib1
#These are any extra library files that I need for building my source .cpp files to final .so product
${CMAKE_SOURCE_DIR}/lib/libfastcv.a
# Links the target library to the log library
# included in the NDK.
${log-lib})
Then build.gradle it should be mentioned what abi formats we want it to make to make sure you pre built .a files are compatible.
flavorDimensions "version"
productFlavors {
create("arm7") {
ndk.abiFilters("armeabi-v7a")
}
Finally, as a note, the below command did not work to filter abis and above command work, even though they look similar in logic and form to me:
cmake {
cppFlags "-std=c++11"
abiFilters 'armeabi-v7a'
}
}
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your APK.
// This is not working to eliminate
abiFilters 'armeabi-v7a'
}
}
I have a library that can both be used as an header-only library and as a traditional library. To enable this optional-header-only functionality, the library includes .cpp source files if compiled in header-only mode. Example:
// Vector.hpp
// (Module file), intended to be included manually by the user
#ifndef LIBRARY_MODULE_VECTOR
#define LIBRARY_MODULE_VECTOR
#include "Library/Vector/Inc/Vector2.hpp"
#include "Library/Vector/Inc/Vector3.hpp"
#include "Library/Vector/Inc/VectorUtils.hpp"
#if defined(LIBRARY_HEADERONLY)
#include "Library/Vector/Src/Vector2.cpp"
#include "Library/Vector/Src/Vector3.cpp"
#include "Library/Vector/Src/VectorUtils.cpp"
#endif
#endif
When the user includes Vector.hpp in one of his/her projects, if LIBRARY_HEADERONLY is defined, the implementation source files will be included right after the header files. Careful usage of the inline keyword is applied to avoid multiple definitions.
If LIBRARY_HEADERONLY is undefined, the .cpp files will be compiled and the library will have to be linked.
My build system of choice is CMake.
Using a CMake flag, the user can define or undefine LIBRARY_HEADERONLY.
The CMakeLists.txt file is similar to this:
# (not shown) set flag and cache variables...
# Include library directory
include_directories("./${INCLUDE_DIRECTORY}")
# Glob all library header/source files
file(GLOB_RECURSE SRC_LIST "${INC_DIR}/*" "${SRC_DIR}/*")
# (Not shown) Check if header-only mode is enabled
# (from now on we assume header-only mode is enabled and that
# LIBRARY_HEADERONLY is defined)
# Use all source/header files as a library target
add_library(HEADER_ONLY_TARGET STATIC ${SRC_LIST})
set_target_properties(HEADER_ONLY_TARGET PROPERTIES LINKER_LANGUAGE CXX)
install(DIRECTORY ${INC_DIR} DESTINATION .)
Unfortunately, the CMake-generated makefile always compiles the .cpp files, even when header-only mode is enabled and the target is HEADER_ONLY_TARGET.
How can I prevent the CMake-generated makefile from compiling the source files in header-only mode?
Note that IDEs reliant on CMake-generated output, such as Qt Creator, should display both the header and source files as part of the project.
If I don't glob any source file, but only the .hpp header files, CMake will complain that no source files were selected for a library target, and IDEs that rely on CMake files will not display any item.
Try setting the source files' HEADER_FILE_ONLY property to prevent them from building, e.g.:
if (LIBRARY_HEADERONLY)
set_source_files_properties(${SRC_LIST} PROPERTIES HEADER_FILE_ONLY 1)
...
endif()
Also see the documentation.
if (Create_Header_Only)
add_library(TargetName INTERFACE)
# Clients will build with -DLIBRARY_HEADERONLY
target_compile_definitions(TargetName INTERFACE LIBRARY_HEADERONLY)
else()
add_library(TargetName STATIC thesource.cpp)
endif()
# Clients will build with -Iinclude
target_include_directories(TargetName INTERFACE include)
Client code just does:
add_executable(mine main.cpp)
target_link_libraries(mine TargetName)
See also Transitive Usage Requirements and all the rest of those CMake manuals regarding creating packages, etc.
An approach of defining all library types and letting the consumer choose between them is outlined in:
Opt-in header-only libraries with CMake
Something like:
add_library(lib_shared SHARED ...)
add_library(lib_shared STATIC ...)
add_library(lib_iface INTERFACE)
So that the consumer makes the choice of which to link to:
# target_link_libraries(consumer lib_static)
# target_link_libraries(consumer lib_shared)
target_link_libraries(consumer lib_iface)
Why do you not separate the GLOB for HEADERS and SRC files? You could add a dummy.cpp (a empty .cpp file) for creating header-only libraries. I mean:
# Glob all library header files
file(GLOB_RECURSE HEADER_ONLY_LIST "${INC_DIR}/*.hpp")
# Glob all library src files
file(GLOB_RECURSE SRC_ONLY_LIST "${SRC_DIR}/*.cpp")
# Check if LIBRARY_HEADERONLY is defined, so you can filter the target files
if(LIBRARY_HEADERONLY)
set(SRC_LIST ${HEADER_ONLY_LIST} dummy.cpp) # I don't know if it's needed to add a dummy.cpp file with your set_target_properties(HEADER_ONLY_TARGET ...)
else()
set(SRC_LIST ${HEADER_ONLY_LIST} ${SRC_ONLY_LIST})
endif(LIBRARY_HEADERONLY)
# Use all source/header files as a library target
add_library(HEADER_ONLY_TARGET STATIC ${SRC_LIST})
set_target_properties(HEADER_ONLY_TARGET PROPERTIES LINKER_LANGUAGE CXX)
install(DIRECTORY ${INC_DIR} DESTINATION .)
Anyway, CMake 3.X.X gives you the chance for creating INTERFACE libraries (header-only ones).
In my project, I have two versions of the same system library: SysLib1.0 and SysLib2.0. These two libraries are used by other components of the system heavily.
SysLib1.0 headers are located in some directory: /project/include. Here's an example of the contents of the project include directory:
/project/include/syslib/
/project/include/awesomelib/
/project/include/coollib/
So naturally, in CMake, other components use include_directories(/project/include) to gain access to system and other component headers. C++ source code could access the headers like so:
#include <syslib/importantheader.hpp>
SysLib2.0 is installed in a separate location in order to avoid linking issues. SysLib2.0's headers are stored here:
/opt/SysLib2.0/include
So naturally, in CMake, other components which require SysLib2.0 use include_directories(/opt/SysLib2.0/include). C++ source code could access the headers like so:
#include <syslib/importantheader.hpp>
Now we have run into a problem. A new component I'm writing needs access to /project/include in order to access awesomelib, BUT also needs SysLib2.0. This involves including /opt/SysLib2.0/include as well. Now when I say #include <syslib/importantheader.hpp>, that could refer to either version of the library. The compiler yells at me with some redefinition errors, as it should.
Even worse, SysLib1.0 and SysLib2.0 both refer to themselves as syslib/... when looking for headers within their own library, which is just as ambiguous.
Does anyone have an idea of how I could exclude a particular directory from an include path? Even if I am including a parent directory as shown in my example? Any solutions or suggestions are appreciated.
You can create a tree-like directory structure for your project with nested CMakeLists.txt files and include separate directories in different leafs:
Given a directory structure:
A:
|main.cpp
|
|CMakeLists.txt
|
|B-----|
| |CMakeLists.txt
| |b.cpp
|
|C-----|
|CMakeLists.txt
|c.cpp
A/CMakeLists.txt:
add_subdirectory(B)
add_subdirectory(C)
add_executable(exe main.cpp)
target_link_libraries(exe a b)
B/CMakeLists.txt:
include_directories(/project/include)
add_library(b b.cpp)
C/CMakeLists.txt:
include_directories(/opt/SysLib2.0/include)
add_library(c c.cpp)
This way you can include different directories for different source files; pack them up in libraries and link the final target with the libraries
I don't like using one include path for all includes. I would rather the following structure.
include - your own headers
include/awesomelib
include/coollib
3rd - third party libs
3rd/syslib-1.0/include
3rd/syslib-1.0/src
3rd/syslib-2.0/include
3rd/syslib-2.0/src
src - your source
src/awesomelib (depends on syslib-1.0, includes 3rd/syslib-1.0/include)
src/coollib (depends on syslib-2.0, includes 3rd/syslib-2.0/include)
Then you can specify which syslib to use when building a library.