How do I use CMake to make a custom library? - c++

I am trying to make a custom library to install with CMake. This is a personal utilities library so contains things like an extended math library, extended vectors, file IO functions etc.
I am very new to CMake and I am struggling to build/install this as a library. I would like this to be a single output file which I install. And I would like to be able to include it (and all sub libraries) with
#include <MaxLib.h>
and by adding -LMaxLib to my makefile.
My file structure is like this:
- MaxLib.h
- CMakeLists.txt
- File
- File.cpp
- File.h
- CMakeLists.txt
- Geom
- File.cpp
- File.h
- CMakeLists.txt
I have tried compiling the individual sublibraries i.e:
add_library(File SHARED ${CMAKE_CURRENT_SOURCE_DIR}/File.cpp)
target_include_directories(File)
and I have tried joining them all together with:
add_library(${PROJECT_NAME} STATIC
${CMAKE_CURRENT_SOURCE_DIR}/MaxLib.h
)
add_subdirectory(File)
add_subdirectory(Geom)
target_link_libraries(MaxLib File)
target_link_libraries(MaxLib Geom)
And although this compiles and I can install it, the object files for File and Geom are not becoming linked with MaxLib
I get the impression that I'm doing this all wrong... What is the correct way to make a library?
Should I be attempting to make a static or shared library like this?
Should it just be one makefile in the root folder which builds a single static object?
Any advice is welcome! Thanks in advance
Reference to previous question

Related

Collect all header files when compiling static library

I am using Cmake to compile a static version of the library from source.
The source code has a structure that looks like this:
src/
module1/
x.cpp
x.h
...
module2/
y.cpp
y.h
...
and so on...
Compiling a static version of the library is not difficult. However for distribution purposes, I just want to distribute the the headers (x.h, y.h, ...) and static libraries (module1.a, module2.a, ...).
Is there some command in GCC or CMAKE to automatically collect all of the headers and put them into a separate folder?
I am aware that I could manually separate the source and headers, or I could simply distribute all of the code (source and headers), but that is wasteful and undesireable for my particular use case. Alternatively, I could write a pretty simple Python script to do it, but it seems to me that this is probably a pretty common scenario. So I would guess that there is something in Gcc or Cmake to do it.
Note: I am not in charge of maintaining the codebase, so I have no say in how the project is structured. If I was, I could have separated the code into src and include folders.
The best thing to do is have cmake glob and install all your artifacts.
# append to your existing CMakeLists.txt
install(TARGETS module1 module2 #adjust to use your names
ARCHIVE DESTINATION lib)
file(GLOB_RECURSE header_list "*.h") #adjust if necessary
install(FILES ${header_list}
DESTINATION include)
Be aware that globbing isn't perfect, and the file list is only updated when cmake is run (i.e., it won't detect added or removed files on its own).

Link with archive that contains other static library archive files

I am trying to use the NBIS library from NIST:
http://www.nist.gov/itl/iad/ig/nbis.cfm
NBIS is composed of several different related libraries that they compile into multiple archive files. They give you an option when installing it to install either all of the individual .a files or to bundle them into a single, monolithic .a file. I had been using the multiple library files but decided to try to use the single, monolithic file to make things easier. But I am getting an error when trying to link against it when using -lnbis in my link step (using g++, which uses ld):
libnbis.a: error adding symbols: Archive has no index; run ranlib to add one
Looking at the archive, it contains the other individual .a files:
$ ar t libnbis.a
liban2k.a
libbozorth3.a
libcblas.a
... and so forth
The line in the Makefile that generates the archive is: $(AR) -ru libnbis.a *.a
I have tried running ranlib libnbis.a and that does not modify it.
So, my question is: How can I link to the NBIS library? I know which individual libraries inside the libnbis.a file I need to link to if I need that. Will it work this way? Or are NIST doing something wrong trying to merge their individual libraries into one archive file?
I have tried searching around to find similar problems and it seems like the answer to the above is that they are doing it wrong. For instance, answers to this question suggest unpacking the individual .a files and repacking the .o files into the conglomerate archive:
How to merge two "ar" static libraries into one
There is also a comment suggesting using libtool:
https://stackoverflow.com/a/8170851/196561
So it looks like I have a couple options if I want to build the libnbis.a file myself. I just wanted to make sure there was not some way to use the .a files in the archive as-is before I do that.

Cmake project with multiple directories and multiple CMakeLists

I have been given some C++ source files, together with a CMakeLists.txt file, which compile to create an executable. I now want to add my own source files to this project. However, I want to keep the original source files, and the original CMakeLists file, separate from the new files.
So, I want my solution to look like this:
/Project
/Project/src
/Project/src/CMakeLists.txt
/Project/src/OriginalSource
/Project/src/OriginalSource/CMakeLists.txt
/Project/src/OriginalSource/Original.cpp
/Project/src/NewSource
/Project/src/NewSource/CMakeLists.txt
/Project/src/NewSource/New.cpp
/Project/build
I want all the source files to then compile into an executable to be placed in the build directory. So my question is, what do I put in the three CMakeLists files, such that src/OriginalSource/CMakeLists.txt just compiles the original sources, src/NewSource/CMakeLists.txt just compiles the new sources, and src/CMakeLists.txt links together all these built sources, and creates an executable?
You could create a convenience library out of your code and then link it to the code you've already got. The idea is explained here.
Please see this link for more details:
http://www.cmake.org/Wiki/CMake/Tutorials/Object_Library
I hope it helps.
No way to change the executable project in OriginSource without modifying the CMakeLists.txt in it. If you really do not want to modify the original project, you could write a new CMakeLists.txt including old and new sources.
One trick is define new sources in /Project/src/CMakeLists.txt, then include them in /Project/src/OriginalSource/CMakeLists.txt:
set(NEW_INCS ${CMAKE_SOURCE_DIR)/NewSource)
file(GLOB NEW_SRCS ${CMAKE_SOURCE_DIR)/NewSource/*.cpp)

Cmake produces file extensions in static library archives

I recently switch from Autotools to CMake because CMake seems to be better for cross platform development and what I've noticed is when I build a static library of my C++ code all the files inside have a suffix .cpp.o
ar -t PA8/libgenericTZR.a
genericTZR.cpp.o
I've looked at other libraries built by other tools and they don't do that. I'm not sure if this is really a bad thing but, how can I get CMake to build the static libraries without the .cpp added file extension?
This is my CMake File
add_executable(PA8 ISP_Charges.cpp genericTZR.cpp genericTZR.h)
set(LIBSRC genericTZR.c genericTZR.h)
add_library(genericTZR SHARED ${LIBSRC})
add_library(genericTZR SHARED $<TARGET_OBJECTS:myObjects>)
add_library(genericTZR-static STATIC ${LIBSRC})
set_target_properties(genericTZR-static PROPERTIES OUTPUT_NAME $
install (TARGETS PA8 DESTINATION bin)
install (TARGETS genericTZR genericTZR-static DESTINATION lib)
install (FILES "${PROJECT_BINARY_DIR}/PA8/genericTZR.h" DESTINA$
Thanks
According to this thread on cmake list (and I agree with it), it is not a good idea to try to change the output file names.
Consider the example gave in the link:
add_executable(foo foo.c foo.cpp)
Generated objects would be foo.c.o and foo.cpp.o. They would conflict if you forced them to have just the .o extension.
You can try to use the non-documented, internal, might-change-in-the-future
set(CMAKE_C_OUTPUT_EXTENSION_REPLACE 1)
set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)
I don't know if they're still available or if works at all. I've never used them.
As comments on your post have clarified it, the names inside the static lib aren't really used, you shouldn't worry about them.

The right way to structure my c++ project with cmake?

I have been struggling with this for quite a while, and my adventures with cmake have only resulted in hackish solutions that I am pretty sure are not correct.
I created a library that consists of several files, as follows:
-libfolder
-codepart1folder
-CMakeLists.txt
-codepart1.cpp
-codepart1.hpp
-codepart2folder
-codepart3folder
-lib.cpp
-lib.hpp
-CMakeLists.txt
I wrote a CMakeLists file to compile the library (after some experimentation), and I can generate a lib.a file. Now I would like to include this code as a library in other projects, and access it through the interface in lib.hpp. What is the best way to do this, in terms of directory structure, and what I need to put into CMakeLists.txt in my root project?
My current attempt has been to add -libfolder as a subfolder to my current project, and add the commands:
include_directories(${PROJECT_SOURCE_DIR}/libfolder)
link_directories(${PROJECT_BINARY_DIR}/libfolder)
add_subdirectory(libfolder)
target_link_libraries(project lib)
When I run make, the library compiles fine, but when project.cpp compiles, it complains that it cannot find codepart1.hpp (which is included in lib.hpp, included from project.cpp).
I suspect that this is the wrong way about doing this, but I cannot wade through the CMake documentation and find a good tutorial on setting up projects like this. Please help, CMake gurus!
The clean way to import one CMake project into another is via the find_package command. The package declaration is done by using the export command. An advantage of using find_package is that it eliminates the need to hard-code paths to the package's files.
Regarding the missing hpp file, you didn't include codepart1folder, so it's not on the include path.
Ok, so after consulting a coworker of mine who is a CMake guru, it seems CMake does not have support for what I am trying to do, leaving one with 3 options:
Add all of the dependencies to the parent projects CMakeLists.txt - not very clean, but it will get the thing to work. You'll have to do this for every project you add the code to, and go back and fix things if your library changes.
clean up your library headers. This is done through some compiler hackery. The idea is to forward-declare every class, and use only pointers or boost::shared_ptr, and then include the dependencies only in the cpp file. That way you can build the cpp file using all the findpackage stuff, and you get the bonus of being able to use the lib by only including the header and linking to the library.
Look into build systems. Having portable code and fast code compilation with complex dependencies is not a solved problem! From my investigations it turned out to be quite complicated. I ended up adopting my coworkers build system which he created himself in cmake, using things he picked up from Google.
Looking at your post you don't seem to add 'codepart1folder' to the includes anywhere. How are you including codepart1.hpp as:
#include <codepart1.hpp>
#include "codepart1folder/codepart1.hpp"
I don't think there is a standard accepted way to structure cmake projects. I've looked at a bunch of cmake repos and they tend to have differences. Personally I do the following:
-project
CMakeLists.txt
-build
-cmake
OptionalCmakeModule.cmake
-src
-Main
Main.cpp
Main.hpp
-DataStructs
SomeTree.hpp
SomeObject.hpp
-Debug
Debug.hpp
-UI
Window.hpp
Window.cpp
Basically that dumps all the source code into 1 directory, then you perform an out of source build with: 'mkdir build && cd build && cmake .. && make' in the projects root folder.
If you have separate libs as part of your project, then you might want a separate libs directory with another subfolder for your specific lib.
I have some of my repos on: https://github.com/dcbishop/ if you want to look at the CMakeLists.txt files.
The main problems with my project structure are that I use the FILE_GLOB which is apparently the 'wrong' way to do things (if you add files after running 'cmake ..' then they won't be picked up hen you do a 'make'). I haven't figured out what the 'right' way to do it is (from what I can see it involves keeping a separate list of files) I also only use 1 CMakeLists.txt file.
Some projects also choose to separate their cpp and hpp files into separate directories. So you would have an include and src folders (at least for the hpp files that are intended to be used externally). I think that would mainly be for projects that are mainly large libraries. Would also make installing header files much easier.
You are probably missing
include_directories(${PROJECT_SOURCE_DIR}/libfolder/codepart1folder)
In such a case you might want to set( CMAKE_INCLUDE_CURRENT_DIR on) to add all folders to the include directory path variable.
Check cmake's output on the command line whether the correct include folders are set or not. Additionally you can always use message() as "print debugging" for cmake variables.
In case of include directories however you need to read the directory property to see what is actually in the include directories.
get_property(inc_dirs DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
message("inc_dirs = ${inc_dirs}")
I hope this helps you figuring out what is missing.
Edit
I just saw your comment about added codepart1folder in the libfolder. It is only available in the libfolder's include_directory path and not propagated to the root folder.
Since the include codepart1.hpp is present in the lib.hpp however you need to have it also available in the project path otherwise you will get missing declaration errors when you build your project.