動機

最近被autoconf弄,所以來記錄一下各種make 如果需要範例code在github上

手工

header是給compiler看,但不管實際上有沒有這些函數的實作

之後是透過linker去static或是dynamic的地方找code

這次的範例是有三個cpp(與各自的header)

  1. 一個主程式 : main.cpp
  2. static 的 函數 : stc.cpp
  3. dynamic 的 函數 : dyn.cpp

編的方式 給I:去哪找header 給L:去哪找so 給l:用哪個library(像libdyn.so就是-ldyn)

g++ -c -o syn.o syn.cpp
g++ -fPIC -shared -o libdyn.so dyn.cpp
g++ -I. -o main main.cpp sta.o libdyn.so
LD_LIBRARY_PATH=. ./main # LD_LIBRARY_PATH is to indicate where to search .so file

make

makefile的邏輯很簡單

  1. 每個target都有對應要編的檔案
  2. 再編檔案之前都要看前提有沒有滿足

而Makefile為了方便有一些自訂的變數,像

  1. $@: target的名字
  2. $^: 整串前提
  3. $<: 所有前提的第一項

那PHONY是為了什麼存在的? clean沒有對應的檔案,但可以當成一個假的target去跑

main: main.cpp sta.o dyn.so
	g++ -I. -o $@ $^

dyn.so: dyn.cpp
	g++ -fPIC -shared -o $@ $^
%.o: %.cpp
	g++ -c -o $@ $<
	# current , first
clean:
	rm *.o *.so

.PHONY: clean

autoconf

整個步驟如下

  1. autoscan
  2. mv configure.scan configure.in
  3. 改 configure.in
  4. 寫 Makefile.am
  5. autoreconf -i
  6. ./configure
  7. make

很長,也很眼花撩亂

先看configure.in,主要是看有EDIT或是ADD的那幾行

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
#AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_INIT(main, 1.0.0, 123456@gmail.com) # EDIT
AC_CONFIG_SRCDIR([main.cpp])
AM_INIT_AUTOMAKE([foreign -Wall -Werror])  # EDIT, optional
AC_CONFIG_HEADERS([config.h])
# autoreconf complain ,so add this line
AC_CONFIG_MACRO_DIRS([m4]) # ADD this to stop complaining

# Checks for programs.
AC_PROG_CXX
AC_PROG_CC

# Checks for libraries.
LT_INIT # ADD this, cuz we have .so file

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

再來是Makefile.am,同樣看註解

AUTOMAKE_OPTIONS=foreign  
# autoreconf complain, so add this line
ACLOCAL_AMFLAGS = -I m4
# program !!
bin_PROGRAMS=main 
main_SOURCES=main.cpp sta.cpp 
include_HEADERS = sta.h dyn.h
# Add out .so file
lib_LTLIBRARIES = libdyn.la
libdyn_la_SOURCES = dyn.cpp
# link .so file after compiling has done
LDADD = libdyn.la

cmake

人性化的多,只要一個CMakeLists.txt,就沒事了

比較需要注意的是CMAKE_SOURCE_DIR與CMAKE_BINARY_DIR

Assuming that you have 2 folders src and build where src contains your projects and build is the empty folder that you just created so you can deploy your out-of-tree build in it: CMAKE_SOURCE_DIR is the path to src where CMAKE_BINARY_DIR points to build.

CMAKE_CURRENT_SOURCE_DIR => CMakeLists.txt在? CMAKE_CURRENT_BINARY_DIR => cmake正在哪裡跑?

感覺這根本不用解釋,看就懂了

cmake_minimum_required (VERSION 3.16)
project(main CXX)
include_directories( ${CMAKE_SOURCE_DIR} )
link_directories( ${CMAKE_SOURCE_DIR} )
set(main_SOURCES
    main.cpp
    sta.cpp
)
add_library(dyn
            SHARED
            dyn.cpp
)
set(main_LIBS
    dyn
)
add_executable( ${PROJECT_NAME} ${main_SOURCES} )
target_link_libraries( ${PROJECT_NAME} ${main_LIBS} )

Ref

CMake 入門 cmake与autoconf+automake的对比 构建Make,Automake,CMake Using Automake and Autoconf xmake vs cmake对比分析 Where is CMAKE_SOURCE_DIR?