c, c++用makefile编译工程



1.、该Makefile 是我自己写的,可用于编译均是 .c文件的工程,基本不用修改什么东西。

2、将该文件拷贝到工程文件夹下,在终端执行:

#make create (将会在根目录下创建出include, src, bin 三个目录)

#make 即可编译

#make clean  删除所有生成的中间文件和可执行文件

3、如果需要编译C++.cppC语言的.c文件,即C++混合编译,将CC=gcc 改为CC=g++即可。(如果还不行,那就需要在.cpp文件的extern C中将被调用的.c声明一下,或者将所有.c文件做成成静态库,后者适合.c文件较多的情况)

CC=gcc

CFLAGS=-o

PARAM=-Wall

CUR=$(shell pwd)

SRC=$(CUR)/src

SRCS=$(SRC)/*.c

TARGET=$(CUR)/bin/exe

.PHONY:$(TARGET)

all:$(TARGET)

$(TARGET):$(SRCS)

$(CC) $^ $(CFLAGS) $@ $(PARAM)

clean:

@-rm -rf $(TARGET)

@-rm -rf $(CUR)/include/*~

@-rm -rf $(SRC)/*~

@-rm -rf $(CUR)/*~

create:

@-mkdir src/

@-mkdir include/

@-mkdir bin/

----------------------------------------------------------

本文给出万能Makefile的具体实现,以及对其中的关键点进行解析。所谓C++万能Makefile,即可编译链接所有的C++程序,而只需作很少的修改。

号称万能Makefile,一统江湖。我对原版的Makefile做了些修改。首先揭开它的庐山真面目:

####################################################
# Generic makefile - 万能Makefile
# for compiling and linking C++ projects on Linux 
# Author: George Foot  Modified:Jackie Lee
####################################################
### Customising
#
# Adjust the following if necessary; EXECUTABLE is the target
# executable's filename, and LIBS is a list of libraries to link in
# (e.g. alleg, stdcx, iostr, etc). You can override these on make's
# command line of course, if you prefer to do it that way.
#
#
EXECUTABLE := main    # 可执行文件名
LIBDIR:=              # 静态库目录
LIBS :=               # 静态库文件名
INCLUDES:=.           # 头文件目录
SRCDIR:=              # 除了当前目录外,其他的源代码文件目录
#
# # Now alter any implicit rules' variables if you like, e.g.:

CC:=g++
CFLAGS := -g -Wall -O3
CPPFLAGS := $(CFLAGS)
CPPFLAGS += $(addprefix -I,$(INCLUDES))
CPPFLAGS += -MMD
#
# # The next bit checks to see whether rm is in your djgpp bin
# # directory; if not it uses del instead, but this can cause (harmless)
# # `File not found' error messages. If you are not using DOS at all,
# # set the variable to something which will unquestioningly remove
# # files.
#

RM-F := rm -f


# # You shouldn't need to change anything below this point.
#
SRCS := $(wildcard *.cpp) $(wildcard $(addsuffix /*.cpp, $(SRCDIR)))
OBJS := $(patsubst %.cpp,%.o,$(SRCS))
DEPS := $(patsubst %.o,%.d,$(OBJS))
MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS))
MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.cpp,$(MISSING_DEPS)))


.PHONY : all deps objs clean veryclean rebuild info

all: $(EXECUTABLE)

deps : $(DEPS)

objs : $(OBJS)

clean :
        @$(RM-F) *.o
        @$(RM-F) *.d
veryclean: clean
        @$(RM-F) $(EXECUTABLE)

rebuild: veryclean all
ifneq ($(MISSING_DEPS),)
$(MISSING_DEPS) :
        @$(RM-F) $(patsubst %.d,%.o,$@)
endif
-include $(DEPS)
$(EXECUTABLE) : $(OBJS)
        $(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -L,$(LIBDIR)) $(addprefix -l,$(LIBS))

info:
        @echo $(SRCS)
        @echo $(OBJS)
        @echo $(DEPS)
        @echo $(MISSING_DEPS)
        @echo $(MISSING_DEPS_SOURCES)

注:1)命令行前的空白符必须为一个制表符(Tab);如,@$(RM-F) *.o前不是空格,而是一个制表符;

内容解析

1.Makefile基本语法

target为要生成的目标文件;dependency为target的依赖文件;command为用于生成target的命令行;

<target> : <dependency> <dependency> ...
(tab)<command>
(tab)<command>
 .
 .
 .

2.赋值符号 := 与 =

  :=与=的区别在于,符号:=表示立即展开变量值。例如:

A:=foo

B:=$(A)

A:=bar

这时,B的值仍为foo,因为它已被展开,不会再随A的值改变而改变。

3.符号#是Makefile的注释符号

4.wildcard函数

SRCS:=$(wildcard *.cpp) 表示列举当前目录中扩展名为.cpp的所有文件,然后赋值给变量SRCS。详细请google之。

5.patsubst函数

OBJS := $(patsubst %.cpp,%.o,$(SRCS))表示,将$(SRCS)中所有满足模式%.cpp的字符串替换为%.o。

6.filter-out函数

$(filter-out $(A),$(B))表示从B中过滤掉A中的内容,返回剩余内容;

7. “.PHONY”

用.PHONY修饰的target是“伪目标”,不需要生成真实的文件;make假定phony target是已经生成的,然后更新它后边的依赖文件和执行它下边的命令(command);

8.all deps objs clean veryclean rebuild info

这些都是“伪目标”。

all是第一个目标,所以输入make时它被默认执行;all生成或更新所有*.cpp文件对应的*.d文件和*.o文件,并链接所有*.o文件生成可执行文件$(EXECUTABLE)。

deps仅仅生成*.d文件;.d文件是什么文件?它包含了代码文件的依赖信息。

objs仅仅生成*.o文件;.o文件是C++代码编译后的中间结果文件,废话!

clean用于删除*.d文件和*.o文件。

veryclean删除*.d文件、*.o文件,还有名为$(EXECUTABLE)的可执行文件。

rebuild先调用veryclean清除结果文件,再调用all重新编译和链接。

info查看某些信息。

使用方法:

make deps即可执行deps;

9.ifneq...else...endif

条件语句,ifneq表示如果不想等,则...;

10.include <files>语句

include表示把<files>的内容包含进来;

$(DEPS)是包含依赖信息的文件,每个源文件对应一个.d文件;-include $(DEPS)表示把这些依赖信息包含进来;

11.链接*.o文件,生成可执行文件

主菜来了!

$(EXECUTABLE) : $(OBJS)
        $(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -l,$(LIBS))

 

$(EXECUTABLE)为可执行文件名;$(OBJS)为所有.o文件名;$(CC)在这里是g++;$(addprefix -l,$(LIBS)添加引用库;

前面说好的*.d文件和*.o文件是怎么生成的呢?貌似没有命令指出要生成它们呀!请看隐含规则!

12. 隐含规则(Implicit rules)

$(EXECUTABLE)依赖于$(OBJS),但makefile中没有指明$(OBJS)依赖于谁,也没指明命令生成它们;

这时,make的隐含规则开始起作用;针对$(OBJS)中的每个目标,make自动调用:

$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ 

依次生成.o文件和.d文件;

$<表示依赖文件列表的第一个文件名;

$@表示目标文件名;

之所以会生成.d文件,是由于“-MMD”这一编译选项。为g++加上这一选项后,编译器会生成文件依赖信息,并存放至.d文件中。

每一个.cpp文件相应地生成一个.d文件和一个.o文件。

13.@符号

命令行前的@符号表示不回显命令行;

14.CFLAGS和CPPFLAGS

这两者包含编译选项,更详细内容请Google之。

-g 添加gdb调试信息;

-Wall 提示warning信息;

-O3 表示第3级优化;


------------------

基本思路:

最外层有三个文件: Makefile, Make.share, Make.include.

每个工程目录中都有一个Makefile文件.

其中最外层的Makefile是外壳部分.需要调用者修改里面的某些参数,例如编译平台,要编译的子目录集合,每个工程都要用到的头文件,编译参数等,设置完成后,会进入每个子目录,执行当前子目录中的Makefile文件.

Make.shareMake.include是供每个工程目中Makefile来包含的,里面包含标准Makefile机制所需要文件的代码.

工程目录下的Makefile : 设置每个工程自己的项目类型(可执行程序,静态库,动态库)和工程模块的名字,自己独特的头文件目录,编译、链接参数.在文件的开头包含最外层的Makefile.include,在文件结尾包含最外层的Makefile.share.

 

最外层的Makefile文件 :

##################################################################################################

##################################################################################################

 

# The target platform information.

# You can change the MACRO 'PLATFORM' or use make : make PLATFORM=[IOS, LINUX, MACOS]

# LINUX MACOS IOS

PLATFORM= LINUX

export PLATFORM

 

# SUB DIRS

SUBDIRS:= \

   ./hello/hellostaticlib \

   ./hello/hellodynamiclib \

   ./hello

 

# ROOT DIR

ROOTDIR:=$(shell pwd)

export ROOTDIR

 

# Global includes

GLOBAL_INCLUDES:= -I$(ROOTDIR)/hello/include

export GLOBAL_INCLUDES

 

# Global flags for compile

GLOBAL_CCXXFLAGS:= -g -DUNICODE -D_UNICODE

export GLOBAL_CCXXFLAGS

 

# Target path

TARGET_PATH:=$(ROOTDIR)/target

export TARGET_PATH

 

# IOS SDK Version

IOSSDK_V= 5.0

export IOSSDK_V

 

#IOS CPU

IOS_ARCH= armv6 armv7 i386

export IOS_ARCH

 

##################################################################################################

##################################################################################################

 

SUPPORTCMDS:= all objs clean cleanall rebuild

export SUPPORTCMDS

 

.PHONY: SUPPORTCMDS ioscombine

 

$(SUPPORTCMDS):

ifeq ($(PLATFORM), IOS)

   for subdir in$(SUBDIRS); do \

       echo "Making " $$subdir; \

       for arch in$(IOS_ARCH); do \

           echo "For " $$arch; \

           (cd $$subdir && make clean && make $@ ARCH=$$arch ); \

       done; \

   done;

else

   for subdir in$(SUBDIRS); do \

       echo "Making " $$subdir; \

       (cd $$subdir && make $@); \

   done;

endif

 

TS=$(notdir $(wildcard $(TARGET_PATH)/$(firstword $(IOS_ARCH))/*))

TSA=$(foreach arch, $(IOS_ARCH), $(foreach ts, $(TS), $(TARGET_PATH)/$(arch)/$(ts)))

ioscombine:

   for ts in$(TS); do \

       echo "Make " $$ts; \

       echo$(TSA) | tr ' ' '\n'| grep $$ts | tr '\n' ' ' | xargs echo; \

       echo$(TSA) | tr ' ' '\n'| grep $$ts | tr '\n' ' ' | xargs lipo -create -output$(TARGET_PATH)/$$ts; \

   done;

 

 

最外层的Makefile文件需要修改的有这几个地方:

PLATFORM : 设置目标的平台. LINUX 代表通用linux系统; MACOS 代表mac系统; IOS 代表IPhone,IPad等IOS设备.

SUBDIRS : 设置工程包含的子模块,每个子模块目录下都有自己的Makefile文件.

GLOBAL_INCLUDES : 项目中各模块都会用到的头文件.

GLOBAL_CCXXFLAGS : 项目中各个模块都会用到的编译连接标志.

TARGET_PATH : 如果有必要,可以修改目标binarary的输出路径.

IOSSDK_V : 如果是IOS系统,需要设置编译IOS程序需要的SDK版本号.

IOS_ARCH : 如果是IOS系统,需要设置编译IOS程序需要支持的CPU类型.最后要调用build ioscombine来生成最终目标文件.

 

最外层的Make.include文件:

##################################################################################################

##################################################################################################

 

ifneq ($(ARCH), "")

 

TARGET_PATH_R:= $(TARGET_PATH)/$(ARCH)

 

endif

最外层的Make.include文件只是修正TARGET_PATH(即目标路径),如果设置了ARCH(CPU类型),依次把不同类型CPU的输入文件放入各自对应的目录中.只是对IOS类型有效.因此暂时IOS才会用到多CPU支持.

 

最外层的Make.share文件:

##################################################################################################

##################################################################################################

 

# The source file types (headers excluded).

# At least one type should be specified.

# The valid suffixes are among of .c, .C, .cc, .cpp, .CPP, .c++, .cp, or .cxx.

SRCEXTS:=.c .cpp

 

# DONT Modify.

SRCDIR:=./

 

# The include dirs.

INCLUDES_ALL :=$(GLOBAL_INCLUDES)

INCLUDES_ALL +=$(INCLUDES)

 

# The flags used for c and c++.

# Wall -Werror # show all warnings and take them as errors

# -fvisibility=hidden # hide the so's export functions

CCXXFLAGS_ALL:=$(GLOBAL_CCXXFLAGS)

CCXXFLAGS_ALL +=$(CCXXFLAGS)

 

# The compiling flags used only for C.

# If it is a C++ program, no need to set these flags.

# If it is a C and C++ merging program, set these flags for the C parts.

CFLAGS_ALL   :=

CFLAGS_ALL   +=$(CFLAGS)

 

# The compiling flags used only for C++.

# If it is a C program, no need to set these flags.

# If it is a C and C++ merging program, set these flags for the C++ parts.

CXXFLAGS_ALL :=

CXXFLAGS_ALL +=$(CXXFLAGS)

 

# The library and the link options ( C and C++ common).

OFLAGS_ALL   :=

OFLAGS_ALL   +=$(OFLAGS)

 

# The EXT-OBJS that include to the target.

EXOBJS_ALL   :=

EXOBJS_ALL   +=$(EXOBJS)

 

 

# The target file name

TARGET:=$(TARGETNAME).exe

 

ifeq ($(TYPE), staticlib)

TARGET:= lib$(TARGETNAME).a

endif

 

ifeq ($(TYPE), dynamiclib)

TARGET    := lib$(TARGETNAME).dll

OFLAGS_ALL += -shared -fPIC

endif

 

TARGET:= $(TARGET_PATH_R)/$(TARGET)

 

# Modify for different paltform.

## linux

ifeq ($(PLATFORM), LINUX)

CCXXFLAGS_ALL += -DLINUX

endif

## mac os

ifeq ($(PLATFORM), MACOS)

CCXXFLAGS_ALL += -DMACOS

RM= rm

endif

## ios

ifeq ($(PLATFORM), IOS)

CCXXFLAGS_ALL += -DIOS

RM= rm

ifeq ($(ARCH), i386)

DEVROOT=/Developer/Platforms/iPhoneSimulator.platform/Developer

SDKROOT=$(DEVROOT)/SDKs/iPhoneSimulator$(IOSSDK_V).sdk

else

DEVROOT=/Developer/Platforms/iPhoneOS.platform/Developer

SDKROOT=$(DEVROOT)/SDKs/iPhoneOS$(IOSSDK_V).sdk

endif

CC=$(DEVROOT)/usr/bin/gcc -arch$(ARCH)

CXX=$(DEVROOT)/usr/bin/g++ -arch$(ARCH)

CCXXFLAGS_ALL+= -isysroot $(SDKROOT)

OFLAGS_ALL  += -isysroot$(SDKROOT)

endif

 

# Stable Section: usually don't need to be changed. But you can add more.

#=============================================================================

SHELL   = /bin/sh

 

SOURCES1=$(foreach d, $(SRCDIR),$(wildcard $(addprefix $(d)*,$(SRCEXTS))))

SOURCES =$(filter-out $(EXCLUDESRCS), $(SOURCES1))

OBJS    =$(foreach x,$(SRCEXTS), $(patsubst %$(x),%.o,$(filter %$(x),$(SOURCES))))

DEPS    =$(patsubst %.o,%.d,$(OBJS))

 

.PHONY: SUPPORTCMDS

 

all:$(TARGET)

 

# Rules for creating the dependency files (.d).

#---------------------------------------------------

%.d: %.c

   @$(CC) -MM -MD$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CFLAGS_ALL) $<

 

%.d: %.C

   @$(CC) -MM -MD$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CXXFLAGS_ALL) $<

 

%.d: %.cc

   @$(CC) -MM -MD$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CXXFLAGS_ALL) $<

 

%.d: %.cpp

   @$(CC) -MM -MD$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CXXFLAGS_ALL) $<

 

%.d: %.CPP

   @$(CC) -MM -MD$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CXXFLAGS_ALL) $<

 

%.d: %.c++

   @$(CC) -MM -MD$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CXXFLAGS_ALL) $<

 

%.d: %.cp

   @$(CC) -MM -MD$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CXXFLAGS_ALL) $<

 

%.d: %.cxx

   @$(CC) -MM -MD$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CXXFLAGS_ALL) $<

 

# Rules for producing the objects.

#---------------------------------------------------

objs:$(OBJS)

 

%.o: %.c

   $(CC) -c$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CFLAGS_ALL) $<

 

%.o: %.C

   $(CXX) -c$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CXXFLAGS_ALL) $<

 

%.o: %.cc

   $(CXX) -c$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CXXFLAGS_ALL) $<

 

%.o: %.cpp

   $(CXX) -c$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CXXFLAGS_ALL) $<

 

%.o: %.CPP

   $(CXX) -c$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CXXFLAGS_ALL) $<

 

%.o: %.c++

   $(CXX) -c$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CXXFLAGS_ALL) $<

 

%.o: %.cp

   $(CXX) -c$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CXXFLAGS_ALL) $<

 

%.o: %.cxx

   $(CXX) -c$(INCLUDES_ALL)$(CCXXFLAGS_ALL)$(CXXFLAGS_ALL) $<

 

# Rules for producing the executable.

#----------------------------------------------

$(TARGET):$(OBJS)

   echo$(TARGET_PATH_R)

   -mkdir -p$(TARGET_PATH_R)

ifeq ($(TYPE), staticlib)

   for a in$(EXOBJS_ALL); do \

       $(AR) -x $$a; \

   done;

   ls *.o | xargs$(AR)$(ARFLAGS)$(TARGET)

else

ifeq ($(strip $(SRCEXTS)), .c)  # C file

   $(CC) -o$(TARGET)$(OBJS)$(EXOBJS_ALL)$(OFLAGS_ALL)

else                           # C++ file

   $(CXX) -o$(TARGET)$(OBJS)$(EXOBJS_ALL)$(OFLAGS_ALL)

endif  

endif

 

-include$(DEPS)

 

rebuild: clean all

 

clean:

   -$(RM) *.o *.d

 

cleanall: clean

   -@$(RM)$(TARGET)

   -@$(RM) "__.SYMDEF" "__.SYMDEF SORTED"

   -@$(RM) *.so *.a

   -@$(RM) -r$(TARGET_PATH)

最外层的Make.share文件是项目中每个模块文件夹下的Makefile应用文件的主体,一般不需要修改.

SRCEXTS : 要编译的文件的扩展名集合.

SRCDIR : 一定不要修改此处,原因不解释.

TARGET : 代码中会根据不同的类型进行选择.可以修改,但是因为可执行程序链接库文件时候如果用-l参数会查找默认名字为lib<>.<>的文件,所以如果目标为库,就表改了.

    如果目标为应用程序,则扩展名为exe.按正常来说,非windows系统上应该没有扩展名才合乎逻辑,但是这样做起码没明显害处(O(∩_∩)O~).

    如果目标为静态库,则文件格式为lib<modulename>.a

    如果目标为动态库,则文件格式为lib<modulename>.so.这里有个问题:在cygwin环境中,如果动态库扩展名为so,会导致链接此so时候找不到文件,而在真实系统中则没有此问题.但是如果扩展名改为dll则无此问题.

DEVROOT, SDKROOT : 是2011年做项目时候的当时MAC机器上的手持设备路径.如果新的系统路径修改了,自己改过来就是了.

这里还涉及到3个定义:LINUX, MACOS和IOS.在工程的代码中可以根据这三个定义的存在与否判断当前编译的环境.也许,是必须根据这三个定义来判断.否则,...

 

项目中模块下的Makefile文件,标准样式为

##################################################################################################

##################################################################################################

 

include$(ROOTDIR)/Make.include

 

TYPE:= exe

TARGETNAME:= test

 

INCLUDES= -I./ -I./hellostaticlib/ -I./hellodynamiclib/

CCXXFLAGS= -DDEBUG -g

OFLAGS= -L$(TARGET_PATH_R) -lhellod -lhellos 

 

#INCLUDES =

#CCXXFLAGS =

#CFLAGS =

#CXXFLAGS =

#OFLAGS =

#EXOBJS =

#EXCLUDESRCS =

 

 

include$(ROOTDIR)/Make.share

其中两个include所在的行不要修改.

TYPE和TARGETNAME是必选的.

TYPE : 目标模块的类型,可以为为exe, staticlib, dynamiclib.

TARGETNAME : 目标模块的名字.

其他选项为可选项

INCLUDES : 此模块额外需要的头文件目录,格式为 -I<path1> -I<path2> ...

CCXXFLAGS : 此模块中c,c+源代码额外需要的编译选项,例如 -DDEBUG -g.

CFLAGS : 同CCXXFLAGS,只对c代码有效.

CXXFLAGS : 同CCXXFLAGS,只对c++代码有效.

OFLAGS : 此模块额外需要的链接选项,如果要链接其他的库,就在这里设置.

EXOBJS : 如果要添加额外的中间文件(*.o),可以在此添加.

EXCLUDESRCS : 此模块目录中不会被编译链接的文件,以空格分隔.

额外补充

1). 查看依赖

ldd file : 可以查依赖关系.但是在cygwin中如果动态库位so,貌似会出错,如果扩展名为dll则没问题.

 

2).链接动态库有几种方式

在cygwin里,如果动态库扩展名为so,就要链接时候直接添加文件:<path>\<name>.so了.如果扩展名为dll,则可以用-l来链接.

在真实系统中,如果用-l链接动态库,会涉及到运行时候可能找不到so的问题,有几种解决方案.

a) 链接时候用 -Wl,-rpath,<path of so>. 另外据说-rpath可以用-R代替.这样程序运行时候就会在-rpath指定的路径中找so文件,找不到会报错.

b)拷贝so到/lib或者/usr/lib目录下(/usr/local/lib).这需要管理员权限.

c)将so所在路径追加到/etc/ld.so.conf文件中,然后运行sudo ldconfig命令.这也需要管理员权限.

d)执行程序前,修改LD_LIBRARY_PATH环境变量.在linux终端,可以输入:export LD_LIBRARY_PATH=<path of your so file>: $LD_LIBRARY_PATH:

然后再执行可执行程序.可以用echo $LD_LIBRARY_PATH 来查看设置的环境变量.此方法关闭shell失效.

3).gcc,g++参数解释

 -fPIC :表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

 

4)用-l链接库

编译动态库可以像编译静态库那样采用-Lpath -lxx的方式进行, 但这里存在一个问题,如果在path目录下既有动态库又有静态库的时候, 链接器优先选择采用动态库的方式进行编译.比如在同一目录下存在 libx.a 和 libx.so, 那么在链接的时候会优先选择libx.so进行链接. 这也是为什么在com组维护的第三方库(third, third-64)中绝大多数库的产出物中只有.a的存在, 主要就是为了避免在默认情况下使用到.so的库, 导致在上线的时候出现麻烦(特别是一些系统中存在,但又与我们需要使用的版本有出入的库).

链接器中提供了-dn -dy 参数来控制使用的是动态库还是静态库,-dn表示后面使用的是静态库,-dy表示使用的是动态库

例:

g++ -Lpath -Wl,-dn -lx -Wl,-dy -lpthread

这样如果在path路径下有libx.so和libx.a这个时候只会用到 libx.a.

注意在最后的地方如果没有-Wl,-dy 让后面的库都使用动态库,可能会报出 "cannot find -lgcc_s" 的错误,这是由于glibc的.a库和.so库名字不同,--static会自动处理,但是 -Wl,-dy却不会去识别这个问题.

 

5)

链接的时候查找顺序:

  1. -L 指定的路径, 从左到右依次查找
  2. 由 环境变量 LIBRARY_PATH 指定的路径,使用":"分割从左到右依次查找
  3. /etc/ld.so.conf 指定的路径顺序
  4. /lib 和 /usr/lib (64位下是/lib64和/usr/lib64)

动态库调用的查找顺序:

  1. ld的-rpath参数指定的路径, 这是写死在代码中的
  2. ld脚本指定的路径
  3. LD_LIBRARY_PATH 指定的路径
  4. /etc/ld.so.conf 指定的路径
  5. /lib和/usr/lib(64位下是/lib64和/usr/lib64)

一般情况链接的时候我们采用-L的方式指定查找路径, 调用动态链接库的时候采用LD_LIBRARY_PATH的方式指定链接路径.

另外注意一个问题,就是只要查找到第一个就会返回,后面的不会再查找. 比如-L./A -L./B -lx 在A中有libx.a B中有libx.a和libx.so, 这个时候会使用在./A的libx.a 而不会遵循动态库优先的原则,因为./A是先找到的,并且没有同名动态库存在.



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章