Makefile:如何在C中创建静态库和共享库?

时间:2014-11-19 17:51:15

标签: c makefile

女士们,先生们,您好。

我试图在C中创建一个Makefile,它将创建两个库 一个静态,一个共享。
到目前为止,我的Makefile适用于静态部分。

Projet文件结构:

//root
//root/src

另外一点,这个Makefile还在我的根项目目录和/ src目录中创建* .o。 该怎么做只会在/ src目录中创建目标文件?

生成文件:

SNAME   =   libmy_printf_`uname -m`-`uname -s`.a
DNAME   =   libmy_printf_`uname -m`-`uname -s`.so
SRC     =   $(wildcard src/*.c)
OBJ     =   $(SRC:.c=.o)
CC      =   gcc
RM      =   rm -f
CFLAGS  =   -W -Wall -ansi -pedantic -Werror -g3 -fPIC
LDFLAGS = -L. -l$(NAME)

STATIC:     $(OBJ)
            $(CC) -c $(SRC) 
            ar r $(SNAME) $(OBJ) 
            ranlib $(SNAME)

DYNAMIC:    $(OBJ)
            $(CC) -c $(SRC)
            $(CC) -shared -o $(DNAME) $(OBJ)

.PHONY: my_printf_static
my_printf_static:       $(STATIC)

.PHONY: my_printf_dynamic
my_printf_dynamic:      $(DYNAMIC)

.PHONY: all
all:                    my_printf_static my_printf_dynamic

.PHONY: clean
clean:
                        $(RM) $(OBJ)
.PHONY: fclean
fclean:                 clean
                        $(RM) $(SNAME) $(DNAME) 
.PHONY: re
re:                     fclean all  

谢谢!

2 个答案:

答案 0 :(得分:5)

你的makefile可以归结为:

NAME    :=  libmy_printf_$(shell uname -m)-$(shell uname -s)
SNAME   :=  $(NAME).a
DNAME   :=  $(NAME).so
SRC     :=  $(wildcard src/*.c)
OBJ     :=  $(SRC:.c=.o)
CFLAGS  :=  -ansi -pedantic -Wall -W -Werror -g3 -fPIC
LDFLAGS :=  -L.
LDLIBS  :=  -l$(...)

.PHONY: all clean fclean re

all: $(SNAME) $(DNAME)

$(SNAME): $(OBJ)
    $(AR) $(ARFLAGS) $@ $^

$(DNAME): LDFLAGS += -shared
$(DNAME): $(OBJ)
    $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@

clean:
    $(RM) $(OBJ)

fclean: clean
    $(RM) $(SNAME) $(DNAME)

re: fclean all

您应该知道多种事情:

  • 不要使用反引号命令,将$(shell)内置函数与:=赋值运算符结合使用,以防止命令重复运行多次(除非这是理想的行为。)

  • 只使用一个.PHONY特殊规则,放在所有规则之上,并在那里列出。

  • 像您一样重新定义$(CC)$(RM)个变量毫无意义,因为它们已包含您想要的内容。

  • 您撰写了-l$(NAME),但未定义NAME变量。我将其更改为$(...),因为我无法猜到你真正想要的东西,不要忘记处理它。

  • 使用要创建的目标的名称作为相关规则的名称。这样,除非您真的需要,否则不会重新创建目标(通过明确调用cleanfcleanre规则。)

  • -L标志和-l标志不应混合在同一个变量中,除非放在链接命令中的正确位置。实际上你甚至没用过它们。我根据Make隐式规则在LDFLAGSLDLIBS内置变量中明确地将它们分开。

如果您有任何疑问,请继续。


如评论中所述,如果需要从静态库的编译标志中删除-fPIC标志,则应考虑在不同目录中构建目标文件:

编辑:我添加了您的my_printf_staticmy_printf_dynamic规则:

NAME    :=  libmy_printf_$(shell uname -m)-$(shell uname -s)
SNAME   :=  $(NAME).a
DNAME   :=  $(NAME).so
SRC     :=  $(wildcard src/*.c)
SDIR    :=  build-static
SOBJ    :=  $(SRC:src/%.c=$(SDIR)/%.o)
DDIR    :=  build-shared
DOBJ    :=  $(SRC:src/%.c=$(DDIR)/%.o)
CFLAGS  :=  -ansi -pedantic -Wall -Werror -W -g3
LDFLAGS :=  -L.
LDLIBS  :=  -l$(...)

.PHONY: all clean fclean re my_printf_static my_printf_dynamic

all: my_printf_static my_printf_dynamic

my_printf_static: $(SNAME)

my_printf_dynamic: $(DNAME)

$(SNAME): $(SOBJ)
    $(AR) $(ARFLAGS) $@ $^

$(DNAME): CFLAGS += -fPIC
$(DNAME): LDFLAGS += -shared
$(DNAME): $(DOBJ)
    $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@

$(SDIR)/%.o: src/%.c | $(SDIR)
    $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<

$(DDIR)/%.o: src/%.c | $(DDIR)
    $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<

$(SDIR) $(DDIR):
    @mkdir $@

clean:
    $(RM) -r $(SDIR) $(DDIR)

fclean: clean
    $(RM) $(SNAME) $(DNAME)

re: fclean all

答案 1 :(得分:0)

  

该怎么做只会在/ src目录中创建目标文件?

不要运行编译器两次。您的STATICDYNAMIC规则都依赖于$(OBJ),这将导致这些文件由make的隐式规则构建。然后,在此之后,您再次在这些规则中运行编译器。把这些线路拿出来吧。 make通常会打印出要运行的命令,因此您应该了解它在构建日志中发生的原因。