getting cmake to build an external dependency requiring configure && make && make install - cmake

I'd like to build ta-lib via cmake's fetchcontent function in my
CMakeLists.txt
FetchContent_Declare(ta_lib
DOWNLOAD_DIR /tmp
URL http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
CONFIGURE_COMMAND configure
BUILD_COMMAND make
INSTALL_COMMAND "make install"
)
FetchContent_MakeAvailable(ta_lib)
include_directories(${ta_lib_SOURCE_DIR}/include)
...
target_link_libraries(${PROJECT_NAME} PRIVATE ta_lib)
I checked that the script above is able to download and decompress the tar-ball, and populate cmake-build-release/_deps/ta_lib-src with the project source, but it fails to build via the desired configure && make && make install sequence. The cmake build doesn't complain, proceeding normally as in the headers are found, but ultimately fails with -lta_lib not found.
I tried BUILD_IN_SOURCE TRUE as well, however I get the error
External project ta_lib-populate has both BINARY_DIR and BUILD_IN_SOURCE!
How does one get the build and install step to actually kick in?

You are possibly missing a few things.
Your make install command most likely is trying to install to the default path, and that's not what you want. You need to add a prefix, ./configure --prefix <path>, and make it so that it's local to your project, e.g., tmp/, that you can find it later.
One you have that, you need identify where ta_lib is installed and links it manually using the target_link_libraries. Here, you most likely cannot just use ta_lib because it's surely not defined. You need to find the path to the library, if needed. Check your tmp/ folder for a clue, and consult the FetchContent documentation.
Unfortunately, I cannot think of a good example on the top of my head to add here.

Related

How do I use ExternalProject_Add to get a simple make invocation?

I need ExternalProject_Add to invoke just one command for an external project whose makefile does all the needed steps. I need to have that command be "make WITH_OPTION1=no WITH_OPTION2=no" in the directory at the top of the external project's source tree. This is one of a few dozen external projects we use. Most of them fit the model of 'configure; make; make install' but a good third don't and this is one that I thought would be easy.
If I try to have the make command invoked like this:
ExternalProject_Add(build-example
PREFIX "${CMAKE_CURRENT_BINARY_DIR}/example"
DEPENDS ""
SOURCE_DIR "${PROJECT_TOPDIR}/External/example"
CONFIGURE_COMMAND ""
BUILD_COMMAND COMMAND make WITH_OPTION1=no WITH_OPTION2=no
INSTALL_COMMAND "")
The resulting make step is done from the wrong directory and therefore the Makefile is not found.
If I add a -C option to the make command it seems to use the right directory, but it ignores the WITH_OPTION stuff. That doesn't compile properly, because those features use things I don't want to provide, and if it did work, I still don't want those features.
If I then add quotes around the entire desired make command, it goes wrong. Apparently the command is passed to 'sh' in such a way that sh fails.
If I use a mechanism to pass the command into a 'configure-file' step and invoke that file from the BUILD_COMMAND, then CMake actually tries to use a broken CMakeLists.txt file that's in the external project, and I wonder what makes CMake think that it should do so.
I just want to invoke the makefile properly, using CMake to organize that build within the dozens of other builds that have to be done to build the complete project.

Meson build: Add dependency path for executable manually

What I'd like to do, is rather easy: Compile a project using the Meson build system + manually including a dependency.
However, there's one dependency, which I do not want to install to /usr/lib, due to System Integrity Protection on Mac. (I know I can turn this off; I don't want to.)
So basically I wanna do:
g++ -L[path_to_lib] [files...] but use meson instead of g++.
However, this seems to be super complicated. After doing some research and unsuccessfully adding
cc = meson.get_compiler('c')
dep = cc.find_library('granite' dirs: [ [path_to_dep] ])
to my meson.build file (which doesn't work, as it handles libraries, not dependencies)
I'm left feeling rather dumb.
Please help!
I know I could just add the relevant path to $PATH, but that is more than overkill and I refuse to believe that there isn't another nice quick way to do so. (As is with the ancient c compiler...)
You should be able to solve your problem without modifying meson.build file (I mean leave granite as ordinary dependency). meson uses pkg-config to search for dependencies, so if you add your non-standard path containing granite package config file to PKG_CONFIG_PATH it will find it. And in this case granite package config file should be correct, of course, i.e. contain correct library and header paths, which should be correct if you configure installation of granite with something like:
# Configure:
$ cmake -DCMAKE_INSTALL_PREFIX=/some/path...
# Build:
$ make
# Install (need sudo?):
$ make install
$ export PKG_CONFIG_PATH=/some/path...:$PKG_CONFIG_PATH
granite_dep = dependency('granite')
my_app = executable('my_app',
dependencies : [granite_dep]
...
However, note that in case of find_library() according to reference manual:
The result object can be used just like the return value of dependency
So, it should work:
granite_dep = cc.find_library('granite', dirs : [path])
executable(..., dependencies : granite_dep)
But, I recommend standard way that utilizes pkg-config, because granite can also have dependencies that you will not be able to automatically pick up this way.

How to specify target with ExternalProject_Add?

Is it possible to build only a specific target when using ExternalProject? In particular, I need to download and build only the MPI version of the OpenCoarrays library. I tried
ExternalProject_Add(
OpenCoarrays-fallback
EXCLUDE_FROM_ALL 1
URL https://github.com/sourceryinstitute/opencoarrays/archive/1.0.1.tar.gz
BUILD_COMMAND make caf_mpi
)
but it builds both serial and MPI versions. If it is not possible, any hack is also welcome.
make install installs all flows of OpenCoarrays, so even you build only caf_mpi at build stage, caf_single is built automatically on install stage.
For install only caf_mpi library flow you can try to modify package sources using PATCH_COMMAND argument of ExternalProject_add command.
E.g, you may replace content of src/CMakeLists.txt file to this one:
add_subdirectory(mpi)
Probably, this will work.

CMake build & link to library without installing to /usr/local or elsewhere

I'm trying to include an external library in a build environment that uses CMake. I'm not trying to install it on the local system (in fact I'd rather not do that, I don't want /usr/local clogged up with all kinds of libraries); I'd just like to have the resulting libxml2.a available for linking with my executable. I can build it fine with the following in CMakeLists.txt:
set (LIBXML_PATH ${MY_SOURCE_DIR}/libxml2-2.9.1)
add_custom_target (build_libxml ALL
COMMENT "Building libxml"
COMMAND ./configure --prefix=/tmp
COMMAND make
WORKING_DIRECTORY ${LIBXML_PATH}
)
But I'm still having trouble with the following:
1) Is this the right approach in the first place, for the general purpose of getting libraries built with configure and make into a CMake environment?
2) How do I get the resulting library (i.e. libxml2.a) under my build output directory?
3) How can I link to that library for my executable builds?
I tried a fiddly solution with
ADD_LIBRARY( xml2 STATIC libxml2.a )
but it seems like there must be a better way than hauling a whole library's contents into… a library.
Thanks.
You need to make it clearer to CMake what is going on here. All it can see now is that you have some custom command that it will run every time. Instead of using add_custom_target with COMMAND, I've found it better to use add_custom_command.
Something like this:
set (LIBXML_PATH ${MY_SOURCE_DIR}/libxml2-2.9.1)
add_custom_command(
OUTPUT libxml2.a
COMMENT "Building libxml"
COMMAND ./configure --prefix=/tmp
COMMAND make
WORKING_DIRECTORY ${LIBXML_PATH}
)
target_link_libraries(your-program libxml2.a)
By doing it this way, CMake can understand that your custom command's essential product is libxml2.a, and when CMake sees something depending on that, it will run the command (if the library doesn't exist already).

Is there way to tell CMake to generate several install rules?

Using CMake to generate GNU/Makefile as an example, I would like to be able to run different install rules, say make install and make install-doc.
Is there a way to tell CMake to generate this ?
You can add a custom target which invokes the cmake_install.cmake script in the outermost binary directory. This script is also invoked when you run the default install target.
add_custom_target(install-doc
COMMAND "${CMAKE_COMMAND}" "-DBUILD_TYPE=$<CONFIGURATION>"
"-DCOMPONENT=doc" "-P" "${CMAKE_BINARY_DIR}/cmake_install.cmake"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
The desired installation component has to be passed as the CMake variable COMPONENT. The build configuration can be set with the variable BUILD_TYPE. $<CONFIGURATION> is a generator expression which will be replaced by the currently active build configuration.