CMake link_directories from library - xcode

I'm trying to link to a library from another library using CMake and Xcode.
This is an issue for any library, but to make things easier to convey, let's use zlib as an example.
This seems to work for executables as follows:
LINK_DIRECTORIES(${LIB_DIR}/zlib/build/)
ADD_EXECUTABLE(MY_EXECUTABLE ...
And it generates an Xcode project with the setting shown below:
As you can see, the $(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) bit gets added correctly, to the zlib library path.
But if I try to do this:
LINK_DIRECTORIES(${LIB_DIR}/zlib/build/)
ADD_LIBRARY(MY_LIBRARY ...
zlib never gets linked to MY_EXECUTABLE when I link it to MY_LIBRARY
And TARGET_LINK_LIBRARIES after ADD_LIBRARY allows me to link to zlib from MY_LIBRARY but I have to specify the full path, which won't work as the configuration (Debug, Release, etc) as well as the effective platform (iphoneos, iphonesimulator, etc) are factors.
What I want to do is to have zlib added to the Xcode Library Search Paths, with the $(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) bit, as shown above.

Turning my comment into an answer
CMake does support adding the appropriate configuration to paths in multi-configuration environments with generator expressions (see e.g. CMake - Accessing configuration parameters of multiple-configuration generators)
And arguments to target_link_libraries() support the use of generator expressions. So in your case you can make use of the $<CONFIG> generator expression which would look something like this:
TARGET_LINK_LIBRARIES(MY_LIBRARY ${LIB_DIR}/zlib/build/$<CONFIG>/...)
Be aware - if you may have changed some policies - of one note from the target_link_libraries() documentation about policies CMP0003 - Libraries linked via full path no longer produce linker search paths and CMP0004 - Libraries linked may not have leading or trailing whitespace:
Note however, that generator expressions will not be used in OLD
handling of CMP0003 or CMP0004

Related

How can I add command-line options file to CMake compiler flags?

GCC allows for having command-line options passed by a file by #file syntax. Using this the file should be added as prerequisite (aka dependency) to the target.
I'm not finding any reference in CMake docs about argument files, suggesting it's not supported. Or perhaps just takes a little bit more plumbing, e.g. cat file|xargs? Or some way telling CMake explicitly that the file is a prerequisite? I mean "Prerequisite" according to GNU Make terminology. If file contents change I have to rebuild. AKA dependency.
Which is it? And how does it work?
You should just be able to use target_compile_options() or CXX_<LANG>_FLAGS like you normally would.
Since the flags available for different compilers are usually different, you probably will have one for each compiler you support, in which case you can wrap your target_compile_options() calls with if() blocks based on CMAKE_CXX_COMPILER_ID or the MSVC variable, or use the CXX_COMPILER_ID or X_COMPILER_ID generator expressions to use the right file (if you have multiple files for multiple compilers) for the right compiler.
However, I've also noticed before when trying this that using file flags like this doesn't automatically add the file as a dependency to the target (the CMake won't add a rule for the target to rebuild if that file changes), so you might need to do that manually like this:
# wrap this in a function taking `target` as an argument.
get_target_property(sources ${target} SOURCES)
set_property(SOURCE ${sources}
# DIRECTORY "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}"
TARGET_DIRECTORY ${target}
APPEND PROPERTY OBJECT_DEPENDS "${PROJECT_SOURCE_DIR}/path/to/flags/file.txt"
)
The above snippet courtesy of a user in this GitHub issue. It uses the OBJECT_DEPENDS source file property to make every source file of a target depend on the compiler options file. I (and the author of that code snippet) would classify it as a workaround, since it only works for Generators that support OBJECT_DEPENDS. From the CMake docs:
Specifies a semicolon-separated list of full-paths to files on which any object files compiled from this source file depend. On Makefile Generators and the Ninja generator an object file will be recompiled if any of the named files is newer than it. Visual Studio Generators and the Xcode generator cannot implement such compilation dependencies.
I'm not sure at what level of the toolchain it would be best to request that such automatic dependency-tracking functionality be added. According some of the Ninja buildsystem maintainers in the above linked GitHub issue, (if my noob brain is understanding the words they're saying correctly :P), it's something that could be handled by compilers when they generate depfiles given a compile comand for a source file. I'm currently too scared to ask compiler maintainers if that's the case. If you're interested in digging onto the part that CMake plays in orchestrating other tools to get dependency tracking for things like header files and the creation of dependency-tracking files ("depfiles"), you can go to your CMake installation's Modules folder and grep for CMAKE_DEPFILE_FLAGS_. Then use "find in files" at https://github.dev/Kitware/CMake.
Notes: Visual Studio / MSVC's compiler calls these "command files", gcc doesn't seem to have a particular name for them, and clang calls these "configuration files". They all support similar #file syntax. I'm not sure what the history is with that, but many compilers aim to have levels of compatibility (similar interface to) with GCC.
That's all. If you're bored and want to read a bit about how CMake does header dependency detection (which is loosely related here on the topic of depfiles), see this other post of mine.

setting up autotools to link single system library statically

I have a project, where I want to link one of system libraries statically. The project uses GNU build system.
In configure.ac I have:
AC_CHECK_LIB(foobar, foobar_init)
On development machine this library is installed in /usr/lib/x86_64-linux-gnu. It is detected, but it is linked dynamically, which causes issues, as it is not present on some machines. Linking it statically (-Wl,-Bstatic etc.) works fine, but I don't know how to set this up in autotools. I tried forcing this into Makefile.am link flags for the project, but it still gives a preference to dynamic library.
I also tried using --enable-static with ./configure, but it seems to have no effect on system libraries.
If you want to link the whole program statically, then you should pass the --disable-shared option to configure. You might or might not need also to pass --enable-static, depending on the default value for that option (which you can influence via your configure.ac file). You really should consider doing this.
You should also consider making this the installer's problem, not the build system's. Let it be the installer's responsibility to ensure that all the shared libraries needed by the program are provided by the systems where it is installed. This is very common; in fact, it is one of the inspirations for package-management systems such as yum / dnf and apt, and their underlying packaging formats.
If you insist on linking only one library statically, while linking everything else dynamically, then you'll need to jump through a few more hoops. The objective will be to emit link options that cause just that library to be linked statically, without changing other libraries' linking. With the GNU toolchain, and supposing that the program is otherwise being linked dynamically, that would be this combination of options:
-Wl,-Bstatic -lfoobar -Wl,-Bdynamic
Now consider the documentation of the AC_CHECK_LIB() macro:
Macro: AC_CHECK_LIB (library, function, [action-if-found],
[action-if-not-found], [other-libraries])
[...] action-if-found is a list of shell commands to run if the link with the library succeeds; action-if-not-found is a list of shell
commands to run if the link fails. If action-if-found is not
specified, the default action prepends -llibrary to LIBS and defines
'HAVE_LIBlibrary' (in all capitals). [...]
Note in particular the default behavior in the event that the optional arguments are not provided (your present case) -- that's not quite what you want, at least not by itself. I suggest providing at least an alternative behavior for action-if-found case, and you could consider also making configure fail in the action-if-not-found case. The latter is left as an exercise; implementing just the former might look like this:
AC_CHECK_LIB([foobar], [foobar_init], [
LIBS="-Wl,-Bstatic -lfoobar -Wl,-Bdynamic $LIBS"
AC_DEFINE([HAVE_LIBFOOBAR], [1], [Define to 1 if you have libfoobar.])
])
You should also pay attention to the order of your AC_CHECK_LIB() invocations. As its docs go on to say:
This macro is intended to support building LIBS in a right-to-left
(least-dependent to most-dependent) fashion such that library
dependencies are satisfied as a natural side effect of consecutive
tests. Linkers are sensitive to library ordering so the order in which
LIBS is generated is important to reliable detection of libraries.
If you find that you still aren't getting what you want, then have a look at the link commands that make actually executes. You need to understand what's wrong about them before you can determine how to fix the problem.
With all that said, I observe that the above treatment is basically a hack, and it makes your build system much less resilient. It introduces dependencies on GNU toolchain options (which some other toolchains may nevertheless accept), and it assumes dynamic linking is being performed overall. It may be possible to resolve those issues with additional Autoconf code, but I urge you to instead go with one of the first two alternatives I described.

Why do we need cmake?

I don't understand, why do we need cmake to build libraries ? I am sorry if my question is stupid, but i need to use some libraries on Widnows, and what ever library i choose i need to build it and/or compile it with cmake.. What is it for ? Why cant i just #include "path" the things that i need into my project, and than it can be compiled/built at the same time as my project ?
And also, sometimes i needed to install Ruby, Perl, Python all of them some specific version so cmake can build libraries... Why do i need those programs, and will i need them only to build library or later in my project too ? (concrete can i uninstall those programs after building libraries ?)
Building things in c++ on different platforms is a mess currently.
There are several different build system out there and there is no standard way to do this. Just providing a visual studio solution wont help compilation on linux or mac.
If you add a makefile for linux or mac you need to repeat configurations between the solution and the makefiles. Which can result in a lot of maintenance overhead. Also makefiles are not really a good build tool compared to the new ones out there.
That you have only CMake libraries is mostly a coincidence. CMake is though a popular choice currently.
There are several solutions out there to unify builds. CMake is a build tool in a special way. It can create makefiles and build them but you can also tell cmake to create a visual studio solution if you like.
The same goes with external programs. They are the choice of the maintainer of the library you use and there are no standards for things like code generation.
While CMake may not be "the" solution (although the upcoming visual studio 2015 is integrating cmake support) but the trend for those build system which are cross-platform is going more and more in this direction.
To your question why you cannot only include the header:
Few libraries are header only and need to be compiled. Either you can get precompiled libs/dlls and just include the header + add the linker path. This is easier in linux because you can have -dev packages which just install a prebuild library and it's header via the package manager. Windows has no such thing natively.
Or you have to build it yourself with whatever buildtool the library uses.
The short answer is that you don't, but it would probably be difficult to build the project without it.
CMake does not build code, but is instead a build file generator. It was developed by KitWare (during the ITK project around 2000) to make building code across multiple platforms "simpler". It's not an easy language to use (which Kitware openly admits), but it unifies several things that Windows, Mac, and Linux do differently when building code.
On Linux, autoconf is typically used to make build files, which are then compiled by gcc/g++ (and/or clang)
On Windows, you would typically use the Visual Studio IDE and create what they call a "Solution" that is then compiled by msvc (the Microsoft Visual C++ compiler)
On Mac, I admit I am not familiar with the compiler used, but I believe it is something to do with XCode
CMake lets you write a single script you can use to build on multiple machines and specify different options for each.
Like C++, CMake has been divided between traditional/old-style CMake (version < 3.x) and modern CMake (version >= 3.0). Use modern CMake. The following are excellent tutorials:
Effective CMake, by Daniel Pfeifer, C++Now 2017*
Modern CMake Patterns, by Matheiu Ropert, CppCon 2017
Better CMake
CMake Tutorial
*Awarded the most useful talk at the C++Now 2017 Conference
Watch these in the order listed. You will learn what Modern CMake looks like (and old-style CMake) and gain understanding of how
CMake helps you specify build order and dependencies, and
Modern CMake helps prevent creating cyclic dependencies and common bugs while scaling to larger projects.
Additionally, the last video introduces package managers for C++ (useful when using external libraries, like Boost, where you would use the CMake find_package() command), of which the two most common are:
vcpkg, and
Conan
In general,
Think of targets as objects
a. There are two kinds, executables and libraries, which are "constructed" with
add_executable(myexe ...) # Creates an executable target "myexe"
add_library(mylib ...) # Creates a library target "mylib"
Each target has properties, which are variables for the target. However, they are specified with underscores, not dots, and (often) use capital letters
myexe_FOO_PROPERTY # Foo property for myexe target
Functions in CMake can also set some properties on target "objects" (under the hood) when run
target_compile_definitions()/features()/options()
target_sources()
target_include_directories()
target_link_libraries()
CMake is a command language, similar shell scripting, but there's no nesting or piping of commands. Instead
a. Each command (function) is on its own line and does one thing
b. The argument(s) to all commands (functions) are strings
c. Unless the name of a target is explicitly passed to the function, the command applies to the target that was last created
add_executable(myexe ...) # Create exe target
target_compile_definitions(...) # Applies to "myexe"
target_include_directories(...) # Applies to "myexe"
# ...etc.
add_library(mylib ...) # Create lib target
target_sources(...) # Applies to "mylib"
# ...etc.
d. Commands are executed in order, top-to-bottom, (NOTE: if a target needs another target, you must create the target first)
The scope of execution is the currently active CMakeLists.txt file. Additional files can be run (added to the scope) using the add_subdirectory() command
a. This operates much like the shell exec command; the current CMake environment (targets and properties, except PRIVATE properties) are "copied" over into a new scope ("shell"), where additional work is done.
b. However, the "environment" is not the shell environment (CMake target properties are not passed to the shell as environment variables like $PATH). Instead, the CMake language maintains all targets and properties in the top-level global scope CACHE
PRIVATE properties get used by the current module. INTERFACE properties get passed to subdirectory modules. PUBLIC is for the current module and submodules (the property is appropriate for the current module and applies to/should be used by modules that link against it).
target_link_libraries is for direct module dependencies, but it also resolves all transitive dependencies. This means when you link to a library, you gets all the PUBLIC properties of the parent modules as well.
a. If you want to link to a library that has a direct path, you can use target_link_libraries, and
b. if you want to link to a module with a project and take its interface, you also use target_link_libraries
You run CMake on CMakeLists.txt files to generate the build files you want for your system (ninja, Visual Studio solution, Linux make, etc.) and the run those to compile and link the code.

How can I make cmake search for the framework that is located in a user-defined location?

I am now trying to link jpeg framework in MAC with cmake. The problem is that it seems that CMake always search for the jpeg.framework in the system's path while it is supposed to link in a user-defined location. I use the following command to force cmake search the framework in a user-defined folder, but failed:
target_link_libraries(${ProjectNameC} "-framework jpeg")
set_target_properties(${ProjectNameC} PROPERTIES LINK_FLAGS "-F${user_defined_folder}")
I also tried this way:
set_target_properties(${ProjectNameC} PROPERTIES LINK_FLAGS "-F${user_defined_folder} -framework jpeg")
Both solutions failed. I may use find_library(), but as the jpeg framework was created without any auxiliary file for find_library().
Any ideas?
You can use find_package(JPEG required) in conjunction with CMAKE_PREFIX_PATH (documented here).
Note that it's best to avoid putting platform-specific things like -framework into your CMake files if possible, since it makes it difficult to generate working build systems on other platforms.

Cmake add_library with boost source files introduces references to non-existant files

we're building a cross-platform utility which must have a small footprint. We've been pulling header files from boost as and when we need them but now we must link against some boost C++ thread code. The easiest immediate solution was to create our own custom library using CMake's "add_library" command to create a static library composed of some boost thread source files. These compile without any problems.
The difficulty arises when I try to link to this library from an executable. Visual Studio 2008 returns an error saying that it cannot link to "libboost_thread-vc90-mt-sgd-1_40.lib". What really puzzles me is that I've grepped through all the source code and CMake config files and I can't find any reference to this libboost library, leading me to think that this has been autogenerated in some way.
This works OK in Linux, can anyone point out why I'm experiencing these issues in Windows?
#Gearoid
You found the correct reason for your problem, but not the correct solution. The BOOST_AUTO_LINK_NOMANGLE is an internal, i.e. for library authors, definition to control the auto-linking. The user level definition is BOOST_ALL_NO_LIB which when defined disables the auto-linking feature for all Boost Libraries code you use. This is described in the user.hpp configuration header (see user.hpp near the bottom and the Boost Config documentation). You can also control this on a per library level as describe in that header.
Ok, well, it turns out that Boost uses this auto-link feature for Visual Studio which embeds references to a mangled (ie, platform-compiler-mult-threaded, etc) boost library name.
The header file which controls this is called "auto_link.hpp" which lives in the config directory of the boost include tree. There's a special preprocessor definition called "BOOST_AUTO_LINK_NOMANGLE" which toggles this behaviour.
Another triumph of mediocrity for Microsoft.

Resources