Makefile构建共享库

Makefile to build shared library

本文关键字:共享 构建 Makefile      更新时间:2023-10-16

我一直在构建一个C++11库,并且头文件/源文件的数量已经增长到编译程序调用它的程度,需要将20多个.cpp文件传递给g++。我一直在研究共享库,它似乎是最好的解决方案。

然而,由于头/源频繁变化,我希望创建一个makefile,它将自动从头和源生成所有.so文件。

为了更好地演示我要做的事情,我将使用我的一个子库Chrono,并展示我如何手动执行此操作。

我首先像这样创建目标文件,

$ g++ -std=c++11 -fPIC -g -c -Wall ../src/Chrono/cpp/DateTime.cpp
$ g++ -std=c++11 -fPIC -g -c -Wall ../src/Chrono/cpp/Schedule.cpp
$ g++ -std=c++11 -fPIC -g -c -Wall ../src/Chrono/cpp/Duration.cpp
$ g++ -std=c++11 -fPIC -g -c -Wall ../src/Chrono/cpp/DayCount.cpp

所以我现在有DateTime.o, Schedule.o, Duration.oDayCount.o在当前目录。然后创建.so文件

$ g++ -shared -Wl,-soname,libChrono.so.1 -o libChrono.so.1.0.1 DateTime.o Schedule.o Duration.o DayCount.o -lc

然后,

$ rm ./*.o && ldconfig -n ./

所以我的工作目录现在包含libChrono.so.1.0.1和符号链接libChrono.so.1

有相当多的子目录我需要这样做,所以你可以看到,无论何时更改头/源,这很快变得低效。如果有人能帮助我设计一个makefile,通过调用make来完成所有这些,我将不胜感激。

谢谢!

更新:

根据goldilock的建议和一些挖掘,我设法拼凑起来:

CXX=g++
CFLAGS=-std=c++11 
TARGET=./lib/libChrono.so.1.0.1
CHRONODIR=./src/Chrono
CHRONOSRC=$(wildcard $(CHRONODIR)/cpp/*.cpp)
CHRONOOBJ=$(join $(addsuffix ../obj/,  $(dir $(CHRONOSRC))), $(notdir (CHRONOSRC:.cpp=.o)))
all: $(TARGET)
    @true
clean:
    @-rm -f $(TARGET) $(CHRONOOBJ)
./lib/libChrono.so.1.0.1: $(CHRONOOBJ)
    @echo "======================="
    @echo "Creating library file $@"
    @echo "======================="
    @$(CXX) -shared -Wl,-soname,$(join $(basename $@), .1) -o $@ $^ -l
    @echo "-- $@ file created --"
$(CHRONODIR)/cpp/../obj/%.o : $(CHRONOSRC)
    @mkdir -p $(dir $@)
    @echo "============="
    @echo "Compiling $<"
    @$(CXX) $(CFLAGS) -fPIC -g -Wall -c $< -o $@

4 .o文件是在lib/中产生的,但我从ld中得到了多个定义投诉。在我单独编译目标文件之前,这将在一行上展开CHRONOOBJ。什么好主意吗?

幸运的是你包括了问题的根源:

我一直在构建一个c++ 11库,头文件/源文件的数量已经增长到编译程序调用它的程度,需要将20多个.cpp文件传递给c++。

因为这揭示了一个潜在的XY问题。直接的解决方案是将目标文件放入归档文件(也称为。一个静态库)并使用它。

GNU make有一个隐式规则用于创建c++ .o文件。它相当于:

%.o: %.cpp
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $<

意思是,如果你把make DateTime.o放在一个没有重新定义这个的makefile的目录中,它将生成DateTime.o。然而,你可能想在$(CXXFLAGS)中添加一些东西,例如:

CXXFLAGS += -Wall -Wextra --std=c++11

如果您打算坚持使用共享库路由,-fPIC也可以去那里。这一行可以是你的整个makefile。

然而,你也想把它们放在一起,所以你必须首先声明所有的对象和一个组合它们的规则:

OBJS = DateTime.o Schedule.o Duration.o
libChrono.a: $(OBJS)
    ar crvs $@ $^

最后一行(参见man ar)创建了包含$(OBJS)中所有对象的归档文件(libChrono.a)。然后,您可以将它放在相同的目录中(或库路径中的目录)并链接-lChrono,从而对任何程序使用它。只有必要的部分将被提取和编译。这节省了在系统目录中维护共享库的时间。

如果你仍然认为你需要一个共享库,$@$^是自动变量;您可以使用类似的方法创建.so,类似于:

SO_FLAGS = -shared
libChrono.so.1.0.1: $(OBJS)
    $(CXX) $(SO_FLAGS) -Wl,-soname,libChrono.so.1 -o $@ $^ -lc

如果这是你的第一条规则,make将照顾一切:首先构建对象,然后是库。请注意,这个问题已经排除了正常的$(CXXFLAGS),以完全复制问题中的编译器行。