25

I searched on the inet but I did not find any clear answer. Could you point me in the right direction on how to convert a Makefile into a CMakeLists?

I want to do that because I am new both to makefile and to cmake. In my job CMake is more used and since I need to start using one of them I prefer having everything in CMake. I know CMake is generating a Makefile but for me CMake is way easier to read than a Makefile.

I have the following Makefile:

PREFIX ?= /usr/local

CC = gcc
AR = ar

CFLAGS = -std=gnu99 -fPIC -Wall -Wno-unused-parameter -Wno-unused-function -I. -O4

APRILTAG_SRCS := $(shell ls *.c common/*.c)
APRILTAG_HEADERS := $(shell ls *.h common/*.h)
APRILTAG_OBJS := $(APRILTAG_SRCS:%.c=%.o)
TARGETS := libapriltag.a libapriltag.so 
# LIBS := -Lusr/include/flycapture

.PHONY: all
all: $(TARGETS)
    @$(MAKE) -C example all

.PHONY: install
install: libapriltag.so
    @chmod +x install.sh
    @./install.sh $(PREFIX)/lib libapriltag.so #this should be the line that install the library
    @./install.sh $(PREFIX)/include/apriltag $(APRILTAG_HEADERS)
    @sed 's:^prefix=$$:prefix=$(PREFIX):' < apriltag.pc.in > apriltag.pc
    @./install.sh $(PREFIX)/lib/pkgconfig apriltag.pc
    @rm apriltag.pc
    @ldconfig

libapriltag.a: $(APRILTAG_OBJS)
    @echo "   [$@]"
    @$(AR) -cq $@ $(APRILTAG_OBJS)

libapriltag.so: $(APRILTAG_OBJS)
    @echo "   [$@]"
    @$(CC) -fPIC -shared -o $@ $^

%.o: %.c
    @echo "   $@"
    @$(CC) -o $@ -c $< $(CFLAGS)

.PHONY: clean
clean:
    @rm -rf *.o common/*.o $(TARGETS)
    @$(MAKE) -C example clean

I am not asking you to do my job but I would like to have some kind of guide or a good link where to look.

The project contains both C and C++ programming languages.

I started creating a new CMakeLists.txt file, but it is still not working. It gives me the following errors: You have called ADD_LIBRARY for library librapriltag.a without any source files. This typically indicates a problem with your CMakeLists.txt file

-- Configuring done
CMake Error: Cannot determine link language for target "librapriltag.a".
CMake Error: CMake can not determine linker language for target: librapriltag.a
-- Generating done
-- Build files have been written to: .....

The CMakeLists.txt I started creating is the following:

project( apriltag2 C CXX)

cmake_minimum_required(VERSION 2.8)

set(CMAKE_C_FLAGS "-std=gnu99 -fPIC -Wall -Wno-unused-parameter -Wno-unused-function -I. -O4")

include_directories("/home/fschiano/Repositories/apriltag2")
include_directories("/home/fschiano/Repositories/apriltag2/common")

add_library( librapriltag.a )

The CMakeLists.txt which works is the following:

project( apriltag2 )

cmake_minimum_required(VERSION 2.8)

set(CMAKE_C_FLAGS "-std=gnu99 -fPIC -Wall -Wno-unused-parameter -Wno-unused-function -I. -O4")

message("CMAKE_SOURCE_DIR=${CMAKE_SOURCE_DIR}")

file(GLOB apriltag_SRC "*.c")
file(GLOB apriltag_HEADERS "*.h")

set(APRILTAG_SRCS ${apriltag_SRC})
set(APRILTAG_HEADERS ${apriltag_HEADERS})

message(STATUS "CMAKE_CURRENT_LIST_DIR=${CMAKE_CURRENT_LIST_DIR}")

add_library(apriltag STATIC ${APRILTAG_SRCS})

target_include_directories(apriltag PUBLIC ${CMAKE_SOURCE_DIR})
target_compile_options(apriltag PUBLIC -fPIC -Wall -Wno-unused-parameter -Wno-unused-function -O4)

install(TARGETS apriltag
        ARCHIVE DESTINATION lib
        RUNTIME DESTINATION bin
        LIBRARY DESTINATION lib)
install(DIRECTORY CMAKE_CURRENT_LIST_DIR/include/
        DESTINATION CMAKE_CURRENT_LIST_DIR/include/
        FILES_MATCHING PATTERN *.h)

EDIT:

Something is still not right. If I want to change something in my library, like something which is in /home/fschiano/Repositories/apriltag2/common If I use the Makefile which I had before doing all these modifications and I do:

  1. make

  2. do some modifications in the files I wanted to modify

  3. sudo make install, which would give me the following output:

    /usr/local/lib/libapriltag.so
    /usr/local/include/apriltag/apriltag.h
    /usr/local/include/apriltag/common/g2d.h
    /usr/local/include/apriltag/common/getopt.h
    /usr/local/include/apriltag/common/homography.h
    /usr/local/include/apriltag/common/image_f32.h
    /usr/local/include/apriltag/common/image_u8.h
    /usr/local/include/apriltag/common/image_u8x3.h
    /usr/local/include/apriltag/common/matd.h
    /usr/local/include/apriltag/common/math_util.h
    /usr/local/include/apriltag/common/pnm.h
    /usr/local/include/apriltag/common/postscript_utils.h
    /usr/local/include/apriltag/common/string_util.h
    /usr/local/include/apriltag/common/svd22.h
    /usr/local/include/apriltag/common/thash_impl.h
    /usr/local/include/apriltag/common/timeprofile.h
    /usr/local/include/apriltag/common/time_util.h
    /usr/local/include/apriltag/common/unionfind.h
    /usr/local/include/apriltag/common/workerpool.h
    /usr/local/include/apriltag/common/zarray.h
    /usr/local/include/apriltag/common/zhash.h
    /usr/local/include/apriltag/common/zmaxheap.h
    /usr/local/include/apriltag/tag16h5.h
    /usr/local/include/apriltag/tag25h7.h
    /usr/local/include/apriltag/tag25h9.h
    /usr/local/include/apriltag/tag36artoolkit.h
    /usr/local/include/apriltag/tag36h10.h
    /usr/local/include/apriltag/tag36h11.h
    /usr/local/lib/pkgconfig/apriltag.pc
    /sbin/ldconfig.real: /usr/lib/libstdc++.so.5 is not a symbolic link
    
    

and the modifications would take effect.

Now, if I remove the Makefile and I do:

  1. cmake .

  2. make

  3. do some modifications in the files I wanted to modify

  4. sudo make install, it gives me the following output:

    Install the project... -- Install configuration: "" -- Up-to-date: /usr/local/lib/libapriltag.a

So it seems that the install part of the CMakeLists.txt is not right!

The file install.sh is the following.

#!/bin/sh -e
# Usage: install.sh TARGET [RELATIVE PATHS ...]
#
# e.g. ./install.sh /usr/local foo/file1 foo/file2 ...
# This creates the files /usr/local/foo/file1 and /usr/local/foo/file2

TARGETDIR=$1
shift

for src in "$@"; do
    dest=$TARGETDIR/$src
    mkdir -p $(dirname $dest)
    cp $src $dest
    echo $dest
done

Could you try to help me? Thanks

desmond13
  • 2,913
  • 3
  • 29
  • 46
  • 5
    Why can't you keep using a GNU Makefile (since `cmake` is generating one, and you already got yours)? For your particular project, what would be the advantage of switching to `cmake`? Please **edit your question** to improve it and motivate it. – Basile Starynkevitch Nov 29 '16 at 08:15
  • BTW, `$(shell ls *.c common/*.c)` should really be `$(wildcard *.c common/*.c)` – Basile Starynkevitch Nov 29 '16 at 08:16
  • 10
    \**sigh\** there are _lots_ of advantages to CMake over just Make - cross platform compatibility, the fact it compiles to something like Ninja (which is much faster), easier to convey more standardized workflows, the fact you can manage dependencies much easier than in Makefiles, automatic configuration is supplied out of box (with `*.cmake` files), etc. It's not the perfect build system/generator (I've had a ton of gripes with it myself over the years) but it beats makefiles in all but the _simplest_ of projects. I'm tired of people acting like CMake is useless. Let them ask the question. – Qix - MONICA WAS MISTREATED Nov 29 '16 at 08:23
  • As I wrote, I am new to both of them. That is why I would like to make my effort to learn only one of them. I am not a programmer and it is not my field of expertise. I need something that works and it is readable. For example, this thing that qtcreator doesn't get my includes I am quite sure is solvable with something in a CMakeLists.txt but I don't know how to do that. – desmond13 Nov 29 '16 at 08:26
  • 2
    ... out of source builds by default, IDE projects being built up (not something I use personally, but I know it comes in handy for many), I don't have to guess at `make all` or `make build` or `make package` or `make clean` or just `make` or `./configure` and _then_ `make` - it's literally just `cmake ../ && cmake --build .` every time; error messages actually make sense when something is wrong, easier to configure different variants... I could go on. – Qix - MONICA WAS MISTREATED Nov 29 '16 at 08:27
  • 1
    @minidiable In that case, stick with CMake. Makefiles are useful in certain cases but they're old and haven't really seen much progress over the last few decades. CMake is going to be much more intuitive even though you have to wrestle with it sometimes. – Qix - MONICA WAS MISTREATED Nov 29 '16 at 08:29
  • @Qix that is what everyone is telling me and what I am seeing around and what made me decide to try to stick with CMake. But I still need to get rid of this makefile that I do not really understand. Thanks for the help. – desmond13 Nov 29 '16 at 08:39
  • 1
    Start reading the documentation. [add_library](https://cmake.org/cmake/help/latest/command/add_library) clearly states that you have to specify the source files necessary to generate the given library. Also, you don't have to specify the prefix (lib) and the extension (.a), but you have to specify if you want to have your library static or shared for example. Don't keep modifying your question with new questions, just ask new questions if they are relevant. – Antonio Nov 29 '16 at 09:00
  • Question of advantage of CMake over make could appear only of fundamental misunderstanding their differences. Make is outdated system-locked build toolchain. CMake is cross-platform build systems generator, standard de-facto for cross-platform C/C++ solutions. CMake guidelines consider libraries without CMake support as a bug and encourage implement CMakeLists for them –  Sep 11 '18 at 16:35

2 Answers2

14

Let's go through that step-by-step:

PREFIX ?= /usr/local

We ignore that, as it's the default. Can be overwritten by CMAKE_INSTALL_PREFIX.

CC = gcc
AR = ar

Ignore these as well. Use CMAKE_C_COMPILER and CMAKE_CXX_COMPILER to forcibly switch the compiler.

CFLAGS = -std=gnu99 -fPIC -Wall -Wno-unused-parameter -Wno-unused-function -I. -O4

They are pretty special for gcc-like compilers. Set them conditionally for CMAKE_C_COMPILER_ID MATCHES GNU further down after defining the target. The standard is set by set(C_STANDARD 98) and set(CXX_STANDARD 98).

APRILTAG_SRCS := $(shell ls *.c common/*.c)

Define a variable listing all the source files individually: set(APRILTAG_SRCS ...)

APRILTAG_HEADERS := $(shell ls *.h common/*.h)

Define a variable listing all the header file individually: set(APRILTAG_HEADERS ...). However, you don't really need them anywhere (unless you want Visual Studio to list them).

APRILTAG_OBJS := $(APRILTAG_SRCS:%.c=%.o)

In most cases, you don't need that. For those rare cases there are Object Libraries.

TARGETS := libapriltag.a libapriltag.so 
# LIBS := -Lusr/include/flycapture

We define our libraries here with add_library:

add_library(apriltag ${APRILTAG_SRCS})
target_include_directories(apriltag PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include/apriltag)
target_compile_options(apriltag PUBLIC -fPIC -Wall -Wno-unused-parameter -Wno-unused-function -O4)

The switch between static and shared is done via BUILD_SHARED_LIBS on invocation of CMake.

.PHONY: all
all: $(TARGETS)
    @$(MAKE) -C example all

Nothing to do here. CMake will automatically create that.

.PHONY: install
install: libapriltag.so
    @chmod +x install.sh
    @./install.sh $(PREFIX)/lib libapriltag.so #this should be the line that install the library
    @./install.sh $(PREFIX)/include/apriltag $(APRILTAG_HEADERS)
    @sed 's:^prefix=$$:prefix=$(PREFIX):' < apriltag.pc.in > apriltag.pc
    @./install.sh $(PREFIX)/lib/pkgconfig apriltag.pc
    @rm apriltag.pc
    @ldconfig

CMake will ease this up by a magnitude:

install(TARGETS apriltag
        ARCHIVE DESTINATION lib
        RUNTIME DESTINATION bin
        LIBRARY DESTINATION lib)
install(DIRECTORY include/
        DESTINATION include/
        FILES_MATCHING PATTERN *.h)

That will install the library static and shared library (whatever exists) and the header files.

libapriltag.a: $(APRILTAG_OBJS)
    @echo "   [$@]"
    @$(AR) -cq $@ $(APRILTAG_OBJS)

libapriltag.so: $(APRILTAG_OBJS)
    @echo "   [$@]"
    @$(CC) -fPIC -shared -o $@ $^

%.o: %.c
    @echo "   $@"
    @$(CC) -o $@ -c $< $(CFLAGS)

All this is not needed.

.PHONY: clean
clean:
    @rm -rf *.o common/*.o $(TARGETS)
    @$(MAKE) -C example clean

You don't need that. CMake will generate a clean target automatically.

Graham
  • 7,431
  • 18
  • 59
  • 84
Torbjörn
  • 5,512
  • 7
  • 46
  • 73
  • Thanks for taking the time of replying me, but still there is something I am not able to understand. I updated the CMakeLists.txt with your suggestions but I still have the following error: CMake Error at CMakeLists.txt:19 (target_include_directories): target_include_directories called with invalid arguments CMake Error at CMakeLists.txt:20 (target_compile_options): target_compile_options called with invalid arguments I will put the new CMakeLists.txt in the original question. – desmond13 Nov 29 '16 at 10:43
  • I tried to put: target_include_directories(apriltag PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include/apriltag) target_compile_options(apriltag PUBLIC -fPIC -Wall -Wno-unused-parameter -Wno-unused-function -O4) But then it gives me other errors. – desmond13 Nov 29 '16 at 10:46
  • Hi, I still have some problems. Everything is working except the install part. I will edit my question to make it more clear what I am still missing. – desmond13 Dec 01 '16 at 13:06
  • Would be great if there was a before/after... hard to follow for beginner – Anton Mar 18 '22 at 20:43
5

Judging from TARGETS := libapriltag.a libapriltag.so, you'll defintely need add_library command to create targets.

Instead of gathering souces to be compiled using wildcards like APRILTAG_SRCS := $(shell ls *.c common/*.c) it is recommended to list them explicitly in add_library call. But if you really want to list them automatically, see file(GLOB ...) command. (There are some important things to be aware of, though, see Specify source files globally with GLOB?).

The clean target would be generated automatically by CMake.

Finally, see the documentation for install() command to create install rules.

Compiler flags are set using set(CMAKE_C_FLAGS "blabla"), or appended using set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} blabla").

Graham
  • 7,431
  • 18
  • 59
  • 84
arrowd
  • 33,231
  • 8
  • 79
  • 110
  • 3
    Don't use `GLOB`. CMake would not be able to detect newly added files to automatically reconfigure your project. – Torbjörn Nov 29 '16 at 08:30
  • 1
    If you use the `CMAKE_C_FLAGS` route as mentioned here, make sure to include the old rules unless you _intend_ to overwrite them all: `set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} blabla")`. Also, agreed with @Torbjörn - globbing isn't amazing in CMake. One of its down sides. – Qix - MONICA WAS MISTREATED Nov 29 '16 at 08:30
  • Instead of setting `CMAKE_C_FLAGS`, I would recommend to set [`CMAKE_C_STANDARD`](http://stackoverflow.com/documentation/cmake/5297/compile-features-and-c-c-standard-selection/25142/c-c-version-selection#t=201611290836142928428) for C version, and to use [`target_compile_options`](https://cmake.org/cmake/help/latest/command/target_compile_options.html) for other flags – rocambille Nov 29 '16 at 08:36
  • Thanks for the reply! add_library( apriltag.a ) works while add_library( apriltag.a apriltag.so ) does not work How can I link them ? – desmond13 Nov 29 '16 at 08:38
  • I will write my new CMakeLists.txt in my original question in this way is more readable. It is still not working of course. – desmond13 Nov 29 '16 at 08:47
  • 1
    Read the documentation for [`add_library`](https://cmake.org/cmake/help/latest/command/add_library) more carefully. Take also a look at SO documentation [here](http://stackoverflow.com/documentation/cmake/3107/build-targets/10593/static-libraries#t=20161129084812063038) and [here](http://stackoverflow.com/documentation/cmake/862/getting-started-with-cmake/23491/hello-world-as-a-library#t=201611290848022637494) – rocambille Nov 29 '16 at 08:49
  • 1
    @minidiable You want two libraries, one `STATIC` and one `SHARED`. You don't have to write the full filename, the prefix `lib` and the extension should be generated automatically. – Karsten Koop Nov 29 '16 at 08:55
  • Thanks, I will read the documentation. Thanks really a lot to everyone helping me. – desmond13 Nov 29 '16 at 08:56