我想更改测试代码的位置(tsnnls_test_DKU.c
),我无法在makefile中进行更改以正确反映此文件夹更改。一些帮助将不胜感激。
我有两个问题: 1)如何链接来自不同子目录的目标文件 2)包括不同的搜索路径(在我的例子中有3个搜索路径)。
在我的orinal设置中,makefile工作正常,我将测试代码tsnnls_test_DKU.c
放在以下位置(第三方库内):
Dir1 = /home/dkumar/libtsnnls-2.3.3/tsnnls
我链接的所有目标文件都在
OBJDir = /home/dkumar/libtsnnls-2.3.3/tsnnls
此外,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
我的makefile工作正常。
但是,我想将测试代码的位置更改为:
Dir4 = /home/dkumar/CPP_ExampleCodes_DKU/Using_tsnnls_DKU/
以下是我的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 $@ $^
尝试运行“$ make”时出现的错误
make: *** No rule to make target `libtsnnls_la-taucs_malloc.o', needed by `tsnnls_test_DKU'. Stop.
显然,我还没能正确使用VPATH。
更新 感谢Mike Kinghan回答我的问题。
答案 0 :(得分:13)
Q1:如何链接来自不同子目录的目标文件?
我们假设您的计划prog
是一个C程序,它将从对象file0.o
,file1.o
链接到
将被编译到子目录obj
中。这是你通常需要的东西
makefile来执行该链接。
$(OBJS) = $(patsubst %.o,obj/%.o,file0.o file1.o)
prog: $(OBJS)
gcc -o $@ $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDLIBS)
这会使$(OBJS)
= obj/file0.o, obj/file1.o
,您只需传递该对象即可
这样的文件到link命令。 Documentation of patsubst
N.B。如果你想要的话,创建 obj
子目录是不够的
将目标文件编译到其中。您必须自己创建或研究如何make
这样做。
Q2:如何包含不同的搜索路径?
这是一个含糊不清的问题 - 模棱两可让你困惑 - 我们必须把它分解为 Q2.a,Q2.b,Q2.c :
Q2.a:如何指定预处理器在源代码中查找#include
编辑的头文件的不同搜索路径?
默认情况下,预处理器将使用内置的标准搜索路径列表查找头文件。你可以看到它们
以详细模式运行预处理器,例如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.
假设您在子目录中有自己的一些头文件
inc
和inc/foo/bar
并希望预处理器搜索这些目录
同样。然后,您需要传递预处理器选项:
-I inc -I inc/foo/bar
到你的编译命令。预处理器选项通常分配给
make变量CPPFLAGS
,例如
CPPFLAGS = -I inc -I inc/foo/bar
(以及您需要的任何其他预处理器选项),并通过此传递 编译命令配方中的变量,例如
gcc -c -o $@ $(CPPFLAGS) $(CFLAGS) $<
N.B。认为CPPFLAGS
是C ++编译器标志的传统make变量是一个常见的错误。
C ++编译器标志的常规make变量是CXXFLAGS
。
您可以通过运行以下来查看-I
选项的效果:
mkdir -p inc/foo/bar # Just to create the path
cpp -v -I inc -I inc/foo/bar
(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:如何指定链接器查找库的不同搜索路径?
假设您有一个库libfoobar.a
,您需要将其与prog
和
它位于目录lib
中,距您的makefile 2级。那么你
需要传递链接器选项:
-L ../../lib
和
-lfoobar
到您的链接命令。第一个将告诉链接器../../lib
是要查看的地方之一
对于图书馆。通常,您通过LDFLAGS
在链接器命令配方中传递此选项。第二个告诉
链接器搜索名为libfoobar.a
的某个库(静态库)或libfoobar.so
(动态库)。通常,您通过LDLIBS
正如预处理器的搜索路径的默认列表一样,有一个默认值 链接器的搜索路径列表。你可以通过运行来看到它们:
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中/
当您需要链接其中一个标准库时,例如libm
(数学库),驻留在其中一个
默认的库搜索路径,您不需要传递任何-L
选项。仅-lm
就可以了。
Q2.c:如何指定make
查找先决条件的不同搜索路径
目标?
N.B。这是关于make
的问题,而不是关于预处理器,编译器或者问题的问题
接头
我们假设您的所有目标文件都将编译到子目录obj
中。
为了在那里编译它们,使用模式规则会很简单:
obj/%.o:%.c
gcc -c -o $@ $(CPPFLAGS) $(CFLAGS) $<
告诉make
,例如obj/file0.o
由file0.c
由食谱制作:
gcc -c -o obj/file0.o $(CPPFLAGS) $(CFLAGS) file0.c
,类似地,对于任何文件obj/*.o
和匹配文件*.c
这很好,因为file0.c
长与makefile位于同一目录中,但是
假设你在其他地方有*.c
个文件?说你的源文件是有条理的
在子目录中,foo/file0.c
和bar/file1.c
。然后make
将无法执行
满足该模式规则并且会说没有规则来制作目标obj / file0.o&#34;,
等
要解决此问题,请使用VPATH
,一个具有特殊含义的make
变量。
如果您将目录名称列表分配给&{39;:&#39;到VPATH
,那么
make
将在每个列出的目录中搜索先决条件
它无法在当前目录中找到它。所以:
VPATH = foo:bar
将导致make
查看当前目录,然后foo
和bar
它会尝试查找.c
个文件以匹配该模式规则。它会成功地满足
规则并将编译必要的源文件。
N.B。您在发布的代码中错误地使用了VPATH
:
VPATH = -L/home/dkumar/libtsnnls-2.3.3/tsnnls
您已使用链接器选项-L
取消了链接器搜索路径,但没有
在那里做生意。
底线:
用于定位头文件的预创建者搜索路径
预处理器的-I<dirname>
选项。将这些选项传递给CPPFLAGS
用于定位库的链接器搜索路径是使用
链接器的-L<dirname>
选项。将这些选项传递到LDFLAGS
make
规则的预先安排的搜索路径在
make
变量VPATH
,作为&#39;: - 标点目录名称列表。
答案 1 :(得分:0)
<强> My answer to part of question
强>
我可以找到如何链接object files from different subdirectory/ subdirectories
;但是,仍然是could not figure out how to use different search path
:
我当前的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 $@ $^