makefile:如何链接来自不同子目录的目标文件并包括不同的搜索路径 [英] makefile : How to link object files from different subdirectory and include different search paths

查看:171
本文介绍了makefile:如何链接来自不同子目录的目标文件并包括不同的搜索路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

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

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

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

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

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

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

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

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

我的makefile正常工作.

and my makefile works fine.

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

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

Dir4 = /home/dkumar/CPP_ExampleCodes_DKU/Using_tsnnls_DKU/

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

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

# 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 $@ $^

尝试运行"$ make"时出现的错误

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

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

很明显,我无法正确使用VPATH.

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

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

UPDATE: Thanks to Mike Kinghan for answering my question.

推荐答案

问题1:如何从其他子目录链接目标文件?

比方说,您的程序prog是C语言程序,它将与对象file0.ofile1.o链接, 将被编译到子目录obj中.这是您通常需要的东西 makefile来执行该链接.

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

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

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

这使得$(OBJS) = obj/file0.o, obj/file1.o,您只需传递对象 链接命令之类的文件. patsubst

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

N.B.如果要在obj子目录中不存在子目录,则不足以创建 将目标文件编译到其中.您必须自己创建它或研究如何使make做到这一点.

N.B. This is not sufficient to create the obj subdirectory 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 make do it.

第二季度:如何包括不同的搜索路径?

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

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:如何指定预处理器将在源代码中查找#include -ed的头文件的不同搜索路径?

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

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

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:

#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.

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

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

-I inc -I inc/foo/bar

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

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

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.一个普遍的错误是认为CPPFLAGS是C ++编译器标志的常规make变量. C ++编译器标志的常规make变量为CXXFLAGS.

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

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

You can see the effect of the -I option by running:

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

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

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

#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:如何在链接程序查找库的地方指定不同的搜索路径?

让我们假设您有一个库libfoobar.a,您需要将其与prog和 它位于目录lib中,该目录比您的makefile高2级.然后你 需要通过链接器选项:

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

-L ../../lib

-lfoobar

链接命令.其中的第一个将告诉链接器../../lib是要查找的地方之一 用于图书馆.按照惯例,您可以通过LDFLAGS在链接器命令配方中传递此选项.第二个告诉 链接器搜索称为libfoobar.a(静态库)或libfoobar.so的某些库 (动态库).按照惯例,您可以通过LDLIBS

to your link command. The first of these will tell the linker that ../../lib is 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

就像预处理器的搜索路径有默认列表一样,默认设置也有 链接程序的搜索路径列表.您可以通过运行以下命令来查看它们:

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'

输出将类似于:

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/

当您需要链接标准库之一时,例如libm(数学库),位于 默认的库搜索路径,则无需传递任何-L选项.单独-lm即可.

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 -L option. -lm alone will do.

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

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

N.B.这是有关make的问题,而不是有关预处理器,编译器或 链接器.

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

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

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/%.o:%.c
    gcc -c -o $@ $(CPPFLAGS) $(CFLAGS) $<

告诉make

obj/file0.ofile0.c由以下配方制成:

which tell make that, e.g. obj/file0.o is made from file0.c by the recipe:

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

,并且类似地适用于任何文件obj/*.o和匹配的文件*.c

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

这很好,只要file0.c与makefile驻留在同一目录中,但是 假设您的*.c文件在其他位置?说您的源文件井井有条 在子目录foo/file0.cbar/file1.c中.然后make将无法 满足该模式规则,并会说没有规则可以使目标obj/file0.o", 等

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

要解决此问题,请使用VPATH,这是一个具有特殊含义的make变量. 如果您为VPATH分配了一个目录名称列表,并用':'进行了标点,则 make会在每个列出的目录中搜索前提条件 它在当前目录中找不到它.所以:

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

VPATH = foo:bar

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

will cause make to look in the current directory, and then foo and bar when it tries to find .c files to match that pattern rule. It will succeed in satisfying the rule and will compile the necessary source files.

N.B.您在发布的代码中错误地使用了VPATH:

N.B. You have used VPATH wrongly in your posted code:

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

您已经为它分配了一个 linker 搜索路径,并带有链接器选项-L,该选项没有 在那里做生意.

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

底线:

  • 用于查找头文件的前驱搜索路径指定为 预处理器的-I<dirname>选项.将这些选项传递给CPPFLAGS

  • 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

用于查找库的链接程序搜索路径是通过 链接器的-L<dirname>选项.将这些选项传递给LDFLAGS

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

make规则的前提条件的搜索路径在 make变量VPATH,作为目录名称的':-标点符号列表.

The search paths for the preprequisities of make rules are specified in the make variable VPATH, as a ':-punctuated list of directory names.

这篇关于makefile:如何链接来自不同子目录的目标文件并包括不同的搜索路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆