make编译时的常见错误
必须承认的是,写代码最痛苦的不是算法,而是环境的安装。
未定义的引用1:缺少头文件
有时候这个变量(比如 ufint16 )是在某个.h文件里定义的,“undefined reference”这时候就是字面意思。
通过
grep -rn "ufint16" *
在目录下搜索这个变量到底在哪里,然后 # include 进来
未定义的引用2:没找这个系统头文件
有时候别人写makefile,它觉得默认大家都装了某个库,所以它就不加显式的包含了。
比如openmp,需要这样:
CFLAGS += -fopenmp
LINKFLAGS += -fopenmp
或者blas等库:
LDLIBS := -lm -lpthread -lglut -lGL -lGLU -lblas -llapack
未定义的引用3:链接库没包括进来
有的库,以前是静态链接的,生成.a 文件,后来它版本更新了,生成.so文件了。
这时候,就需要包括正确的链接库文件进来。
比如,只包括.a文件:
EXTERNAL_LIBS := $(wildcard ../external/lib/*.a)
注意,这里写的wildcard
代表,使用正则匹配;如果不加这个,默认是不会允许正则匹配的。
下面介绍分别介绍静态库、动态库的链接
静态库
凡是make编译之后,生成 .a 文件的,都是静态库。
调用这个库时,只需要把.a文件复制过来,在指定的路径之下,make程序就能看到。
显式制定这些静态库的名字(包含路径)
EXTERNAL_LIBS := $(wildcard ../external/lib/*.a)
然后:
LOADLIBES += \
-Xlinker --start-group \
$(addprefix -Xlinker , $(EXTERNAL_LIBS)) \
-Xlinker --end-group
在gcc语句中,加入
$(LOADLIBES)
就可以了,大概是这个逻辑,没有我写的这么复杂;我是根据我手上的这份代码说明的。
动态库
凡是make编译之后,生成 .so 文件的,都是动态库。
动态库本身还会调用系统的别的库,所以不能,从电脑A复制到电脑B直接使用;这是与静态库不一样的。
动态库体积小一点,因为它动态链接系统的别的库,而不是直接包括进来。
首先,把.so文件(我的是libmetis.so)复制到系统放置so文件的地方,比如linux的:
/usr/lib
然后在makefile里,加上这么一句:
-lmetis
比如:
LDLIBS := -lm -lpthread -lglut -lGL -lGLU -lblas -llapack -lmetis
记得更新下系统的路径:
sudo ldconfig
你应该可以查到这个库了:
ldconfig -p | grep libmetics
看到已经在系统里:
libmetis.so (libc6,x86-64) => /usr/lib/libmetis.so
就可以make了