简体   繁体   English

Makefile建立共享库

[英]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.oSchedule.oDuration.oDayCount.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM