C++ makefile:如何链接来自不同子目录的目标文件并包含不同的搜索路径

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28153873/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 20:54:56  来源:igfitidea点击:

makefile : How to link object files from different subdirectory and include different search paths

c++cmakefilesearch-path

提问by Garima Singh

I want to change the location of my test code (tsnnls_test_DKU.c) and I am unable to make change in makefile to reflect this folder change properly. Some help would be appreciated.

我想更改测试代码 ( tsnnls_test_DKU.c)的位置,但无法在 makefile 中进行更改以正确反映此文件夹更改。一些帮助将不胜感激。

I have two questions:1) How to link object files from different subdirectory 2) include different search paths (3 search paths in my example).

我有两个问题:1)如何链接来自不同子目录的目标文件 2)包括不同的搜索路径(在我的示例中为 3 个搜索路径)。

In my orinal setup, where makefile works fine, I put my test code tsnnls_test_DKU.cat following location (inside the third party libraries):

在我的原始设置中,makefile 工作正常,我将我的测试代码tsnnls_test_DKU.c放在以下位置(在第三方库中):

Dir1 = /home/dkumar/libtsnnls-2.3.3/tsnnls

All object files, that I am linking to, are at

我链接到的所有目标文件都位于

OBJDir = /home/dkumar/libtsnnls-2.3.3/tsnnls

Also, some include file contained in tsnnls_test_DKU.care at following three locations (three search paths):

此外,其中包含的一些包含文件tsnnls_test_DKU.c位于以下三个位置(三个搜索路径):

Dir1 = /home/dkumar/libtsnnls-2.3.3/tsnnls  
Dir2 = /home/dkumar/libtsnnls-2.3.3
Dir3 = /home/dkumar/libtsnnls-2.3.3/tsnnls/taucs_basic

and my makefile works fine.

我的 makefile 工作正常。

However, I would like to change the location of test code to:

但是,我想将测试代码的位置更改为:

Dir4 = /home/dkumar/CPP_ExampleCodes_DKU/Using_tsnnls_DKU/

Here is how my makefile looks like (Updated after inputs from other user:

这是我的 makefile 的样子(在其他用户输入后更新:

# A sample Makefile

VPATH = -L/home/dkumar/libtsnnls-2.3.3/tsnnls
INC_PATH  = -I/home/dkumar/libtsnnls-2.3.3/ -I/home/dkumar/libtsnnls-2.3.3/tsnnls/  -I/home/dkumar/libtsnnls-2.3.3/tsnnls/taucs_basic/

# Here is a simple Make Macro.
LINK_TARGET     = tsnnls_test_DKU
OBJS_LOC    = tsnnls_test_DKU.o

# Here is a Make Macro that uses the backslash to extend to multiple lines.
OBJS =  libtsnnls_la-taucs_malloc.o libtsnnls_la-taucs_ccs_order.o \
    libtsnnls_la-taucs_ccs_ops.o libtsnnls_la-taucs_vec_base.o \
    libtsnnls_la-taucs_complex.o libtsnnls_la-colamd.o \
    libtsnnls_la-amdbar.o libtsnnls_la-amdexa.o \
    libtsnnls_la-amdtru.o libtsnnls_la-genmmd.o \
    libtsnnls_la-taucs_timer.o libtsnnls_la-taucs_sn_llt.o \
    libtsnnls_la-taucs_ccs_base.o libtsnnls_la-tlsqr.o \
    libtsnnls_la-tsnnls.o libtsnnls_la-lsqr.o   \
    $(OBJS_LOC)

REBUILDABLES = $(LINK_TARGET) 

all : $(LINK_TARGET)
    echo All done

clean : 
    rm -f $(REBUILDABLES)   
    echo Clean done

#Inclusion of all libraries
RANLIB = ranlib
STATICLIB= /usr/local/lib/taucs_full/lib/linux/libtaucs.a 

tsnnls_test_LDADD = $(LDADD)
LIBS = -largtable2 -llapack -lblas -lquadmath -lm

$(LINK_TARGET) : $(OBJS)   $(tsnnls_test_LDADD) $(LIBS)  $(STATICLIB)
gcc -g ${INC_PATH} -o $@ $^

The error that I get when trying to run "$make"

尝试运行“$make”时遇到的错误

make: *** No rule to make target `libtsnnls_la-taucs_malloc.o', needed by `tsnnls_test_DKU'.  Stop.

Obviously, I have not been able to use VPATH properly.

显然,我无法正确使用 VPATH。

UPDATE:Thanks to Mike Kinghan for answering my question.

更新:感谢 Mike Kinghan 回答我的问题。

回答by Mike Kinghan

Q1: How to link object files from a different subdirectory?

Q1:如何从不同的子目录链接目标文件?

Let's say your program progis a C program that will be linked from object file0.o, file1.owhich are to be compiled into subdirectory obj. Here is the sort of thing you typically need in your makefile to perform that linkage.

假设您的程序prog是一个 C 程序,它将从 object 链接file0.ofile1.o将被编译到 subdirectory 中obj。以下是您在 makefile 中通常需要的内容来执行该链接。

$(OBJS) = $(patsubst %.o,obj/%.o,file0.o file1.o)

prog: $(OBJS)
    gcc -o $@ $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDLIBS)

This makes $(OBJS)= obj/file0.o, obj/file1.oand you simply pass the object files like that to the link command. Documentation of patsubst

这使得$(OBJS)=obj/file0.o, obj/file1.o并且您只需将这样的目标文件传递给链接命令。文件patsubst

N.B.This is not sufficient to createthe objsubdirectory if it doesn't exist when you want to compile an object file into it. You'll have to create it yourself or study how to make makedo it.

NB如果您想将目标文件编译到子目录中时它不存在,则这不足以创建obj子目录。您必须自己创建它或研究如何制作make它。

Q2: How to include different search paths?

Q2:如何包含不同的搜索路径?

This is an ambiguous question - the ambiguity is confusing you - and we must break it down into Q2.a, Q2.b, Q2.c:

这是一个模棱两可的问题-模棱两可让您感到困惑-我们必须将其分解为Q2.a、Q2.b、Q2.c

Q2.a: How to specify different search paths where the preprocessor will look for header files that are #include-ed in the source code?

Q2.a:如何指定不同的搜索路径,预处理器将在其中查找#include源代码中带有-ed 的头文件?

By default, the preprocessor will look for header files using a built-in a list of standard search paths. You can see them by running the preprocessor in verbose mode, e.g.cpp -v(CTRL-C to terminate). The output will contain something like:

默认情况下,预处理器将使用内置的标准搜索路径列表查找头文件。您可以通过以详细模式运行预处理器来查看它们,例如cpp -v(CTRL-C 终止)。输出将包含如下内容:

#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.

Let's suppose you have some header files of your own in subdirectories incand inc/foo/barand want the preprocessor to search these directories as well. Then you need to pass the preprocessor options:

让我们假设你有你自己的子目录中的某些头文件 incinc/foo/bar并希望预处理器搜索这些目录也。然后你需要传递预处理器选项:

-I inc -I inc/foo/bar

to your compile command. Preprocessor options are conventionally assigned to the make variable CPPFLAGS, e.g.

到您的编译命令。预处理器选项通常分配给 make 变量CPPFLAGS,例如

CPPFLAGS = -I inc -I inc/foo/bar

(along with any other preprocessor options you require), and passed via this variable in the compile command recipe, e.g.

(以及您需要的任何其他预处理器选项),并通过编译命令配方中的此变量传递,例如

gcc -c -o $@ $(CPPFLAGS) $(CFLAGS) $<

N.B.It is a common mistake to think that CPPFLAGSis the conventional make variable for C++ compiler flags. The conventional make variable for C++ compiler flags is CXXFLAGS.

NB认为这CPPFLAGS是 C++ 编译器标志的常规 make 变量是一个常见的错误。C++ 编译器标志的常规 make 变量是CXXFLAGS.

You can see the effect of the -Ioption by running:

您可以-I通过运行来查看该选项的效果:

mkdir -p inc/foo/bar # Just to create the path
cpp -v -I inc -I inc/foo/bar

(CTRL-C to terminate). Now the output will contain the like of:

(CTRL-C 终止)。现在输出将包含以下内容:

#include "..." search starts here:
#include <...> search starts here:
 inc
 inc/foo/bar
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.

Q2.b: How to specify different search paths where the the linker will look for libraries?

Q2.b:如何指定链接器查找库的不同搜索路径?

Let's suppose you are have a library, libfoobar.athat you need to link with progand that it resides in a directory libthat is 2 levels up from your makefile. Then you need to pass the linker options:

假设您有一个libfoobar.a需要链接的库,prog并且它位于lib比您的 makefile 高 2 级的目录中。然后你需要传递链接器选项:

-L ../../lib

and

-lfoobar

to your link command. The first of these will tell the linker that ../../libis one of the places to look for libraries. Conventionally, you pass this option in the linker command recipe via LDFLAGS. The second tells the linker to search for some library called libfoobar.a(a static library) or libfoobar.so(a dynamic library). Conventionally, you pass this option in the linker command recipe via LDLIBS

到您的链接命令。其中第一个将告诉链接器这../../lib是寻找库的地方之一。通常,您可以通过LDFLAGS. 第二个告诉链接器搜索某个名为libfoobar.a(静态库)或libfoobar.so(动态库)的库。通常,您可以通过以下方式在链接器命令配方中传递此选项LDLIBS

Just as there is a default list of search paths for the preprocessor, there is a default list of search paths for the linker. You can see them by running:

正如预处理器有一个默认的搜索路径列表一样,链接器也有一个默认的搜索路径列表。您可以通过运行来查看它们:

gcc -v -Wl,--verbose 2>&1 | grep 'LIBRARY_PATH'

The output will be something like:

输出将类似于:

LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/: /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/: /usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../:/lib/:/usr/lib/

LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/:/ usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr /lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../:/lib/: /usr/lib/

When you need to link one of the standard libraries, e.g. libm(the math library), that resides in one of the the default library search paths, you don't need to pass any -Loption. -lmalone will do.

当您需要链接libm位于默认库搜索路径之一中的标准库之一(例如(数学库))时,您无需传递任何-L选项。-lm一个人就行。

Q2.c: How to specify different search paths where makewill look for the prerequisites of targets?

Q2.c: 如何指定不同的搜索路径在哪里make寻找目标的先决条件?

N.B.This is a question about make, not a question about the preprocessor, compiler, or linker.

注意这是一个关于 的问题make,而不是关于预处理器、编译器或链接器的问题。

We have assumed that all of your object files will be compiled into the subdirectory obj. To get them compiled there, it would be nice and simple just to use the pattern rule:

我们假设您的所有目标文件都将编译到子目录中obj。要在那里编译它们,只需使用模式规则即可:

obj/%.o:%.c
    gcc -c -o $@ $(CPPFLAGS) $(CFLAGS) $<

which tell makethat, e.g. obj/file0.ois made from file0.cby the recipe:

这说明make,例如obj/file0.o是由file0.c配方制成的:

gcc -c -o obj/file0.o $(CPPFLAGS) $(CFLAGS) file0.c

and similarly for any file obj/*.oand matching file *.c

类似地对于任何文件obj/*.o和匹配文件*.c

This is fine as long file0.cresides in the same directory as the makefile, but suppose you have your *.cfiles somewhere else? Say your source files are organised in subdirectories, foo/file0.cand bar/file1.c. Then makewill be unable to satisfy that pattern rule and will say there is "no rule to make target obj/file0.o", etc.

只要file0.c与 makefile 驻留在同一目录中就可以了,但是假设您的*.c文件位于其他地方?假设您的源文件组织在子目录中,foo/file0.c并且bar/file1.c. 然后make将无法满足该模式规则,并会说“没有规则可以制作目标 obj/file0.o”等。

To solve this problem use VPATH, a makevariable that has a special meaning. If you assign a list of directory names, punctuated by ':', to VPATH, then makewill search for a prerequisite in each of the listed directories whenever it can't find it in the current directory. So:

要解决此问题,请使用具有特殊含义VPATHmake变量。如果您分配一个目录名称列表,标点为 ':', to VPATH,那么 make只要在当前目录中找不到它,就会在每个列出的目录中搜索先决条件。所以:

VPATH = foo:bar

will cause maketo look in the current directory, and then fooand barwhen it tries to find .cfiles to match that pattern rule. It will succeed in satisfying the rule and will compile the necessary source files.

会导致make在当前目录查找,然后foobar当它试图找到.c文件,以匹配方式规则。它将成功满足规则并编译必要的源文件。

N.B.You have used VPATHwrongly in your posted code:

注意VPATH在发布的代码中错误地使用了:

VPATH = -L/home/dkumar/libtsnnls-2.3.3/tsnnls

You have asigned a linkersearch path to it, with the linker option -L, which has no business there.

您已经为它分配了一个链接器搜索路径,链接器选项-L在那里没有业务。

Bottom line:

底线:

  • The preprecessor search paths, for locating header files, are specified with the preprocessor's -I<dirname>option. Pass these options to the compile recipe in CPPFLAGS

  • The linker search paths, for locating libraries, are specified with the linker's -L<dirname>option. Pass these options to the linkage recipe in LDFLAGS

  • The search paths for the preprequisities of makerules are specified in the makevariable VPATH, as a ':-punctuated list of directory names.

  • 用于定位头文件的预处理器搜索路径由预处理器的-I<dirname>选项指定。将这些选项传递给编译配方CPPFLAGS

  • 用于定位库的链接器搜索路径由链接器的-L<dirname>选项指定。将这些选项传递给链接配方LDFLAGS

  • make规则先决条件的搜索路径在make变量中指定VPATH,作为目录名称的':-标点列表。

回答by Garima Singh

My answer to part of questionI could find out how to link object files from different subdirectory/ subdirectories; but, still could not figure out how to use different search path:

My answer to part of question我可以找到如何链接object files from different subdirectory/ subdirectories;但是,仍然could not figure out how to use different search path

My current makefile is:

我当前的makefile是:

    # A sample Makefile

OBJS_PATH = /home/dkumar/libtsnnls-2.3.3/tsnnls/
C_INCLUDE_PATH  = -I/home/dkumar/libtsnnls-2.3.3/ -I/home/dkumar/libtsnnls-2.3.3/tsnnls/  -I/home/dkumar/libtsnnls-2.3.3/tsnnls/taucs_basic/
CPATH  = -I/home/dkumar/libtsnnls-2.3.3/ -I/home/dkumar/libtsnnls-2.3.3/tsnnls/  -I/home/dkumar/libtsnnls-2.3.3/tsnnls/taucs_basic/

# Here is a simple Make Macro.
LINK_TARGET     = tsnnls_test_DKU
OBJS_LOC    = tsnnls_test_DKU.o

# Here is a Make Macro that uses the backslash to extend to multiple lines.
OBJS =  libtsnnls_la-taucs_malloc.o libtsnnls_la-taucs_ccs_order.o \
    libtsnnls_la-taucs_ccs_ops.o libtsnnls_la-taucs_vec_base.o \
    libtsnnls_la-taucs_complex.o libtsnnls_la-colamd.o \
    libtsnnls_la-amdbar.o libtsnnls_la-amdexa.o \
    libtsnnls_la-amdtru.o libtsnnls_la-genmmd.o \
    libtsnnls_la-taucs_timer.o libtsnnls_la-taucs_sn_llt.o \
    libtsnnls_la-taucs_ccs_base.o libtsnnls_la-tlsqr.o \
    libtsnnls_la-tsnnls.o libtsnnls_la-lsqr.o   

 ## adding "$(OBJS_PATH)" to each word in "$(OBJS)"
# which in our case is basically to add the same folder in front of all "*.o" object files.
OBJS2 = $(addprefix $(OBJS_PATH)/, $(OBJS)) 


# OBJS_LOC is in current working directory,
OBJS_ALL = $(OBJS2) \
    $(OBJS_LOC)

## DKU IS COPING THIS FROM ORIGINAL MAKEFILE THAT ARE GENERATED USING /home/dkumar/libtsnnls-2.3.3/tsnnls/MAKEFILE.AM
RANLIB = ranlib
STATICLIB= /usr/local/lib/taucs_full/lib/linux/libtaucs.a 

tsnnls_test_LDADD = $(LDADD)
LIBS = -largtable2 -llapack -lblas -lquadmath -lm


REBUILDABLES = $(OBJS_LOC) $(LINK_TARGET) 


all : $(LINK_TARGET)
    echo All done

clean : 
    rm -f $(REBUILDABLES)   
    echo Clean done

# Here is a Rule that uses some built-in Make Macros in its command:
$(LINK_TARGET) : $(OBJS_ALL)   $(tsnnls_test_LDADD) $(LIBS)  $(STATICLIB)
    gcc -g -o $@ $^