[英]Makefile to build shared library
I've been building a C++11
library, and the number of header/source files has grown to the point where compiling programs invoking it, entails passing 20+ .cpp
files to g++
. 我一直在构建C++11
库,并且头文件/源文件的数量已经增长到编译调用它的程序的程度,这需要将20多个.cpp
文件传递给g++
。 I've been reading up on shared libraries and it seems to be the best solution. 我一直在阅读共享库,这似乎是最好的解决方案。
However, as headers/source change frequently, I'm hoping to create a makefile
that would automatically generate all the .so
files from the headers and source. 但是,由于头文件/源文件经常更改,因此我希望创建一个makefile
,该makefile
将自动从头文件和源文件生成所有.so
文件。
To better demonstrate what I'm trying to do, I'll take one of my sub-libraries, Chrono
and show how I would do this manually. 为了更好地演示我要执行的操作,我将使用我的一个子库Chrono
并演示如何手动执行此操作。
I first create the object files like so, 我首先像这样创建目标文件,
$ 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
So that I now have DateTime.o
, Schedule.o
, Duration.o
, and DayCount.o
in the current directory. 这样,我现在在当前目录中就有DateTime.o
, Schedule.o
, Duration.o
和DayCount.o
。 I then create the .so
file, 然后,我创建.so
文件,
$ g++ -shared -Wl,-soname,libChrono.so.1 -o libChrono.so.1.0.1 DateTime.o Schedule.o Duration.o DayCount.o -lc
I then go, 然后我去
$ rm ./*.o && ldconfig -n ./
So that my working directory now contains, libChrono.so.1.0.1
and the symlink libChrono.so.1
. 现在,我的工作目录包含libChrono.so.1.0.1
和符号链接libChrono.so.1
。
There are quite a few subdirectories I need to do this for, so you can see that this quickly grows inefficient whenever changes to headers/source are made. 我需要为此执行很多子目录,因此您可以看到,只要对标头/源进行了更改,它就会迅速变得效率低下。 I would be grateful if anyone can help me design a makefile that accomplishes all this simply by invoking make
. 如果有人可以帮助我设计一个只需通过调用make
即可完成所有这些工作的makefile,我将不胜感激。
Thanks! 谢谢!
UPDATE: 更新:
Based on goldilock's advice and some digging, I managed to bang together: 根据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
files are produced in lib/
but I get multiple definition complaints from ld
. 4 .o
文件在lib/
中生成,但是我从ld
收到多个定义投诉。 Before I was compiling the object files separately, but this unwinds CHRONOOBJ
on one line. 在我分别编译目标文件之前,但这将CHRONOOBJ
展开为一行。 Any ideas? 有任何想法吗?
Fortunately you included the origin of your problem: 幸运的是,您包括了问题的根源:
I've been building a C++11 library, and the number of header/source files has grown to the point where compiling programs invoking it, entails passing 20+ .cpp files to g++. 我一直在构建C ++ 11库,并且头文件/源文件的数量已经增长到编译调用它的程序的程度,这需要将20多个.cpp文件传递给g ++。
Because this reveals a potential XY problem . 因为这揭示了潜在的XY问题 。 The straightforward solution to this is to put object files into an archive (aka. a static library) and use that. 对此的直接解决方案是将目标文件放入归档文件(也称为静态库)中并使用它。
GNU make has an implicit rule for creating C++ .o
files. GNU make具有创建C ++ .o
文件的隐式规则 。 It amounts to this: 它等于:
%.o: %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $<
Meaning, if you make DateTime.o
in a directory with a makefile that doesn't redefine this, it will make DateTime.o
. 也就是说,如果你make DateTime.o
与生成文件的目录中未重新定义这一点,就会使DateTime.o
。 You may want to add things to $(CXXFLAGS)
however, eg: 您可能想将内容添加到$(CXXFLAGS)
中,例如:
CXXFLAGS += -Wall -Wextra --std=c++11
If you intend to stick with the shared lib route, -fPIC
can go there too. 如果您打算使用共享库路由,则-fPIC
也可以到那里。 That one line could be your entire makefile. 那一行可能是您的整个makefile。
However, you also want to put these together, so you must first declare all the objects and a rule for combining them: 但是,您还希望将它们放在一起,因此必须首先声明所有对象和组合它们的规则:
OBJS = DateTime.o Schedule.o Duration.o
libChrono.a: $(OBJS)
ar crvs $@ $^
This last line (see man ar
) creates the archive (libChrono.a) containing all the objects in $(OBJS)
. 最后一行(请参阅man ar
)创建包含$(OBJS)
中所有对象的档案$(OBJS)
。 You can then use this with whatever program by placing it in the same directory (or a directory in the library path) and linking -lChrono
. 然后,可以通过将其放在相同目录(或库路径中的目录)中并链接-lChrono
,将其与任何程序一起使用。 Only the necessary parts will be extracted and compiled in. This saves you having to maintain a shared lib in a system directory. 仅提取和编译必要的部分。这省去了在系统目录中维护共享库的麻烦。
If you still think you need a shared lib, $@
and $^
are automatic variables ; 如果仍然认为需要共享库,则$@
和$^
是自动变量 ; you can use similar methodology to create a .so
, something along the lines of: 您可以使用类似的方法来创建.so
,类似于以下内容:
SO_FLAGS = -shared
libChrono.so.1.0.1: $(OBJS)
$(CXX) $(SO_FLAGS) -Wl,-soname,libChrono.so.1 -o $@ $^ -lc
If that is your first rule, make
will take care of everything: building first the objects and then the library. 如果这是您的第一条规则, make
会处理所有事情:首先构建对象,然后构建库。 Notice this one has excluded your normal $(CXXFLAGS)
to duplicate exactly the compiler line from the question. 请注意,这一行已排除了您正常的$(CXXFLAGS)
来从问题中完全复制编译器行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.