如何防止我的makefile由于静态库而重新链接

Posted

技术标签:

【中文标题】如何防止我的makefile由于静态库而重新链接【英文标题】:How to prevent my makefile to relink due to static library 【发布时间】:2017-02-19 16:51:07 【问题描述】:

我有一个 Makefile,它在没有要编译的静态库时运行良好:

CC              = g++ -std=c++11                                                                                                                                        

RM              = rm -f                                                                                                                                                 

NAME            = hello                                                                                                                                                                                                                                                                                                                                                                                                                            

SRCS            = Main.cpp \                                                                                                                                            
                  srcs/Controller.cpp \
                  ...                                                                                                         
                  srcs/Parser.cpp                                                                                                                                                                                                                                                               

OBJS            = $(SRCS:.cpp=.o)                                                                                                                                       

CPPFLAGS        += -W -Wall -Wextra -Werror                                                                                                                             

all     : $(NAME)                                                                                                                                                       

$(NAME) : $(OBJS)                                                                                                                                                       
          $(CC) $(CPPFLAGS) $(CFLAGS) -o $(NAME) $(OBJS) -I./inc                                                                                                        

clean   :                                                                                                                                                               
          $(RM) $(OBJS)                                                                                                                                                                                                                                                                                           

fclean  : clean                                                                                                                                                         
          $(RM) $(NAME)                                                                                                                                                 

re      : fclean all                                                                                                                                                    

.PHONY  : all clean fclean re

这个makefile可以工作并且不会重新链接(当我输入两次“make”时,它不会重新编译并输出“Nothing to be done for all”)

但是当我想编译一个静态库时,“make”命令重新编译库而不输出“Nothing to be done for all”,这里是包含静态库的新Makefile:

CC              = g++ -std=c++11                                                                                                                                        

RM              = rm -f                                                                                                                                                 

NAME            = hello                                                                                                                                          

LIBNAME         = libhello.a                                                                                                                                     

SRCS            = srcs/Controller.cpp \
                  ...                                                                                                                                 
                  srcs/Parser.cpp                                                                                                                             

OBJS            = $(SRCS:.cpp=.o)                                                                                                                                       

CPPFLAGS        += -W -Wall -Wextra -Werror                                                                                                                             

all     : $(NAME)                                                                                                                                                       

$(NAME) : $(OBJS)                                                                                                                                                       
          ar rc $(LIBNAME) $(OBJS)
          $(CC) $(CPPFLAGS) $(CFLAGS) -o $(NAME) $(LIBNAME) Main.cpp -I./inc                                                                                                                                                                                                                                                             

clean   :                                                                                                                                                               
          $(RM) $(OBJS)                                                                                                                                                 
          $(RM) $(LIBNAME)                                                                                                                                              

fclean  : clean                                                                                                                                                         
          $(RM) $(NAME)                                                                                                                                                 

re      : fclean all                                                                                                                                                    

.PHONY  : all clean fclean re    

当静态库已经编译并且不需要重新编译时,我该如何解决这个问题以防止重新编译makefile?

非常感谢

【问题讨论】:

【参考方案1】:

关于这个食谱:

$(NAME) : $(OBJS)                                                                                                                                                       
      $(CC) $(CPPFLAGS) $(CFLAGS) -o $(NAME) $(OBJS) -I./inc  

预计默认编译语句将用于生成目标文件,make 将在执行规则之前生成这些目标文件。并且由于它没有在这个秘籍中执行任何编译,所以不需要参数-I./inc

如果头文件没有在依赖项中列出,更改头文件将导致关联的源文件重新编译失败。

建议:

HEADERS := ..

$(name): $(OBJS) 
<tab> $(CC)  -o $@ $(OBJS) $(LFLAGS)

%.o:%.cpp $(HEADERS)
<tab> $(CC) $(CPPFLAGS) -c $< -o $@ -I./inc 

行内注:

CPPFLAGS        += -W -Wall -Wextra -Werror

-W 关闭所有以前启用的警告,可能不是您想要的,建议删除该参数。

创建静态库时需要考虑类似的问题,类似于:

这一行:

$(NAME) : $(OBJS)                                                                                                                                                       
      ar rc $(LIBNAME) $(OBJS)
      $(CC) $(CPPFLAGS) $(CFLAGS) -o $(NAME) $(LIBNAME) Main.cpp -I./inc 

变成:

HEADER := ...

all: $(LIBNAME) $(NAME)

$(LIBNAME): $(OBJS)
<tab> ar rc -o $@ $^

%.o:%.cpp
<tab> $(CC) $(CPPFLAGS) -c $< -o $@ -I./inc 

$(NAME): main.o $(LIBNAME)
<tab> $(CC) $< -o $@ $(LFLAGS) -l$(LIBNAME)

【讨论】:

非常感谢您的回答以及您对 -W 标志的说明! @user3629249 你所说的 -W 标志是完全错误的!正如您在man make 中看到的那样:-w Inhibit all warning messages. 和:-Wextra This enables some extra warning flags that are not enabled by -Wall. (This option used to be called -W. The older name is still supported, but the newer name is more descriptive.) 所以-W 标志只是-Wextra 的旧名称(所以把-W-Wextra 放在同一行是没用的,所有Epitech ' 学生犯了同样的错误,因为他们无法自己思考,他们只是复制了 Intranet 的 Makefile 的示例。 @Paul-Marie,此选项:-W 导致:禁止所有警告消息。这可以在网页上找到:-W @user3629249 是的,但就像我告诉你的那样,你正在交换 -w-W-w 标志有效地导致“禁止所有警告”,但 -W(所以大写)只是-Wextra 的旧名称,仍然受到支持,但不能保证它在未来会保持这种状态! (请参阅您网页上的第一行描述)。最佳后卫。 现在我明白了,大写字母 'W' .vs.小写“w”。我的错误【参考方案2】:

问题在于 $NAME 由于这条规则而成为虚假目标:

all     : $(NAME)

我认为可以通过将其更改为实际目标来解决该问题:

all     : $(LIBNAME)

另外,你有这个规则:

$(NAME) : $(OBJS)
      ar rc $(LIBNAME) $(OBJS)
      $(CC) $(CPPFLAGS) $(CFLAGS) -o $(NAME) $(LIBNAME) Main.cpp -I./inc

这有点令人困惑:该库构建为$LIBNAME,但随后它继续链接名为$NAME 的可执行文件。因此,每次您对Main.cpp 进行更改时,都必须重新构建库。

【讨论】:

【参考方案3】:

您对$(NAME) 的规则实际上并没有创建一个名为$(NAME) 的文件(即hello),因此make 每次都会尝试重新制作它。配方必须符合规则(这就是为什么您应该使用自动变量,如下面的最后一个示例):

all: $(LIBNAME)
$(LIBNAME): $(OBJS)
  ar rc $(LIBNAME) $(OBJS)

GNU make 也有内置的归档功能,虽然它不能很好地与并行 make 配合使用:

ARFLAGS := rc
all: $(LIBNAME)($(OBJS))

一种更惯用的、并行安全的方式类似于

ARFLAGS := rc
.PHONY: all
all: $(LIBNAME)
$(LIBNAME): $(OBJS)
  $(AR) $(ARFLAGS) $@ $^

【讨论】:

以上是关于如何防止我的makefile由于静态库而重新链接的主要内容,如果未能解决你的问题,请参考以下文章

当目标是静态库而目标链接是静态库时,target_link_libraries 会做啥

当我链接动态库而不是静态库时,CMake 有效

Linux2.6 如何编写Makefile,使驱动程序能够编译链接静态库

Makefile“重新链接”是啥意思? [关闭]

链接构建的静态库而不是使用 add_subdirectory?

在linux下写makefile时,如何链接一个静态库?