【问题标题】:Convert Makefile into CMakeLists, where to start将 Makefile 转换为 CMakeLists,从哪里开始
【发布时间】:2017-04-13 03:32:10
【问题描述】:

我在inet上搜索,但没有找到任何明确的答案。您能否指出如何将 Makefile 转换为 CMakeLists 的正确方向?

我想这样做是因为我对 makefile 和 cmake 都是新手。在我的工作中,CMake 被更多地使用,因为我需要开始使用其中一个,所以我更喜欢在 CMake 中拥有一切。我知道 CMake 正在生成一个 Makefile,但对我来说,CMake 比 Makefile 更容易阅读。

我有以下 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

我不是要你做我的工作,但我想有一些指南或一个很好的链接去哪里看。

该项目同时包含 C 和 C++ 编程语言。

我开始创建一个新的 CMakeLists.txt 文件,但它仍然无法正常工作。它给了我以下错误: 您为库 librapriltag.a 调用了 ADD_LIBRARY,但没有任何源文件。这通常表明您的 CMakeLists.txt 文件存在问题

-- 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: .....

我开始创建的 CMakeLists.txt 如下:

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 )

有效的 CMakeLists.txt 如下:

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)

编辑:

还是有些不对劲。如果我想更改我的库中的某些内容,例如 /home/fschiano/Repositories/apriltag2/common 中的内容 如果我使用在进行所有这些修改之前拥有的 Makefile 并且我会这样做:

  1. 制作

  2. 对我要修改的文件进行一些修改

  3. sudo make install,它会给我以下输出:

    /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
    
    

修改将生效。

现在,如果我删除 Makefile 并这样做:

  1. cmake .

  2. 制作

  3. 对我要修改的文件进行一些修改

  4. sudo make install,它给了我以下输出:

    安装项目... -- 安装配置:“” -- 最新:/usr/local/lib/libapriltag.a

看来是CMakeLists.txt的安装部分不对!

install.sh 文件如下。

#!/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

你能帮帮我吗? 谢谢

【问题讨论】:

  • 你为什么不能继续使用 GNU Makefile(因为cmake 正在生成一个,而你已经有了你的)?对于您的特定项目,切换到cmake 有什么好处?请编辑您的问题以改进它并激发它。
  • *sigh* CMake 与 Make 相比有 很多 的优势 - 跨平台兼容性,事实上它可以编译成 Ninja(其中更快),更容易传达更标准化的工作流程,您可以比在 Makefile 中更轻松地管理依赖项,自动配置是开箱即用的(带有*.cmake 文件)等。它不是完美的构建系统/生成器(这些年来,我自己对它有很多抱怨),但除了最简单的项目之外,它在所有项目中都胜过makefile。我厌倦了人们表现得像 CMake 没用一样。让他们问这个问题。
  • ... 默认情况下没有源代码构建,正在构建 IDE 项目(不是我个人使用的东西,但我知道它对许多人来说很方便),我不必猜测 @ 987654333@ or make build or make package or make clean or just make or ./configure and then make - 每次都只是cmake ../ &amp;&amp; cmake --build .;当出现问题时,错误消息实际上是有意义的,更容易配置不同的变体......我可以继续。
  • @minidiable 在这种情况下,坚持使用 CMake。 Makefile 在某些情况下很有用,但它们已经过时了,在过去的几十年里并没有真正看到太大的进步。 CMake 将变得更加直观,即使您有时不得不与它搏斗。
  • 开始阅读文档。 add_library 明确指出您必须指定生成给定库所需的源文件。此外,您不必指定前缀 (lib) 和扩展名 (.a),但您必须指定是否要让您的库静态或共享,例如。不要不断用新问题修改你的问题,只要提出新问题,如果它们是相关的。

标签: makefile cmake


【解决方案1】:

让我们一步一步来:

PREFIX ?= /usr/local

我们忽略它,因为它是默认设置。可以被CMAKE_INSTALL_PREFIX覆盖。

CC = gcc
AR = ar

也忽略这些。使用CMAKE_C_COMPILERCMAKE_CXX_COMPILER强制切换编译器。

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

它们对于类似 gcc 的编译器来说非常特别。在定义目标后,将它们有条件地设置为CMAKE_C_COMPILER_ID MATCHES GNU。 该标准由set(C_STANDARD 98)set(CXX_STANDARD 98) 制定。

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

定义一个单独列出所有源文件的变量:set(APRILTAG_SRCS ...)

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

定义一个单独列出所有头文件的变量:set(APRILTAG_HEADERS ...)。但是,您实际上并不需要它们(除非您希望 Visual Studio 列出它们)。

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

在大多数情况下,您不需要它。对于那些罕见的情况,有Object Libraries

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

我们在这里用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)

staticshared 之间的切换是在调用 CMake 时通过 BUILD_SHARED_LIBS 完成的。

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

这里无事可做。 CMake 会自动创建它。

.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 会大大缓解这个问题:

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

这将安装库静态和共享库(无论是否存在)和头文件。

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

你不需要那个。 CMake 会自动生成一个clean 目标。

【讨论】:

  • 感谢您抽出宝贵时间回复我,但仍有一些我无法理解的地方。我用你的建议更新了 CMakeLists.txt,但我仍然有以下错误: CMakeLists.txt:19 (target_include_directories) 处的 CMake 错误:使用无效参数调用 target_include_directories CMakeLists.txt:20 (target_compile_options) 处的 CMake 错误:target_compile_options 调用无效论据我会将新的 CMakeLists.txt 放在原始问题中。
  • 我试图输入: 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) 但是然后它给了我其他错误。
  • 嗨,我还有一些问题。除安装部分外,一切正常。我将编辑我的问题,以更清楚地说明我仍然缺少什么。
【解决方案2】:

TARGETS := libapriltag.a libapriltag.so来看,你肯定需要add_library命令来创建目标。

建议不要使用APRILTAG_SRCS := $(shell ls *.c common/*.c) 之类的通配符来收集要编译的源,而是在add_library 调用中明确列出它们。但如果您真的想自动列出它们,请参阅file(GLOB ...) 命令。 (不过,有一些重要的事情需要注意,请参阅Specify source files globally with GLOB?)。

clean 目标将由 CMake 自动生成。

最后,查看install() 命令的文档来创建安装规则。

使用set(CMAKE_C_FLAGS "blabla") 设置编译器标志,或使用set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} blabla") 附加。

【讨论】:

  • 不要使用GLOB。 CMake 将无法检测到新添加的文件以自动重新配置您的项目。
  • 如果您使用此处提到的CMAKE_C_FLAGS 路由,请确保包含旧规则,除非您打算将它们全部覆盖:set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} blabla")。此外,同意@Torbjörn - globbing 在 CMake 中并不令人惊奇。它的缺点之一。
  • 我建议不要设置CMAKE_C_FLAGS,而是为C版本设置CMAKE_C_STANDARD,并为其他标志使用target_compile_options
  • 仔细阅读add_library 的文档。还可以查看 SO 文档 herehere
  • @minidiable 你想要两个库,一个STATIC,一个SHARED。你不必写完整的文件名,前缀lib和扩展名应该会自动生成。
猜你喜欢
  • 2011-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 2011-03-23
  • 2011-12-14
相关资源
最近更新 更多