我正在尝试创建一个makefile,它能够用于我希望在我的C项目中拥有的特定文件结构。请参阅下面的makefile以查看结构说明。
如果我运行make bin/obj/list.o
,我会得到标题中指示的输出,即make: *** No rule to make target 'bin/obj/list.o'. Stop.
。
这是我的makefile:
# compiler
CC := gcc
# name of target file
TARGET := main_bin
TEST_TARGET := test_bin
# directories and file info
INCDIR := inc
SRCDIR := src
TARGETDIR := bin
OBJDIR := $(TARGETDIR)/obj
TESTDIR := tests
SRCEXT := c
OBJEXT := o
# flags and libraries
CFLAGS := -Wall -O3 -I $(INCDIR)
CFLAGS_TEST := -Wall -O3 -I $(INCDIR) -I $(TESTDIR)/$(INCDIR)
LIB := -lm
# Want a project structure like:
#
# root
# ---- README
# ---- LICENSE
# ---- MAKEFILE
# ---- .gitignore
# ---- src
# ---- main.c
# ---- dir1
# ---- source1.c
# ---- ...
# ---- dirN
# ---- sourceN.c
# ---- tests
# ---- test_main.c
# ---- inc
# ---- test1.h
# ---- ...
# ---- testN.h
# ---- tests1
# ---- test1.c
# ---- ...
# ---- testsN
# ---- testN.c
# ---- bin
# ---- test_executable
# ---- obj
# ---- test_obj1.o
# ---- ...
# ---- test_objN.o
# ---- inc
# ---- header1.h
# ---- ...
# ---- headerN.h
# ---- bin
# ---- executable
# ---- obj
# ---- obj1.o
# ---- ...
# ---- objN.o
#
# find all src files that aren't in the root of the src directory
SOURCES := $(shell find $(SRCDIR) -mindepth 2 -type f -name '*.$(SRCEXT)')
# find all src files that aren't in the root of the tests directory
TEST_SOURCES := $(shell find $(TESTDIR)/$(SRCDIR) -mindepth 2 -type f -name '*.$(SRCEXT)')
# find the src file that is in the root of the src directory -- will contain main
MAIN_SOURCE := $(shell find $(SRCDIR) -maxdepth 1 -type f -name '*.$(SRCEXT)')
# find the src file that is in the root of the tests directory -- will contain main for tests
TEST_MAIN_SOURCE := $(shell find $(TESTDIR)/$(SRCDIR) -maxdepth 1 -type f -name '*.$(SRCEXT)')
# name the object files
OBJECTS := $(addprefix $(OBJDIR)/,$(notdir $(SOURCES:.$(SRCEXT)=.$(OBJEXT))))
TEST_OBJECTS := $(addprefix $(TESTDIR)/$(OBJDIR)/,$(notdir $(TEST_SOURCES:.$(SRCEXT)=.$(OBJEXT))))
# compile target
all: dirs $(TARGET)
# default to all
default: all
# create obj and bin directories if they don't exist
dirs:
mkdir -p $(TARGETDIR)
mkdir -p $(OBJDIR)
mkdir -p $(TESTDIR)/$(TARGETDIR)
mkdir -p $(TESTDIR)/$(OBJDIR)
# the main program relies on the file containing main under src and the objects
# link the object files into the executable
$(TARGET): $(OBJECTS) $(MAIN_SOURCE)
@echo "Linking..."
$(CC) -o $(TARGETDIR)/$@ $^ $(LIB)
# compile source files under the subdirectories of src into .o object files
$(OBJDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
@echo "Compiling..."
$(CC) $(CFLAGS) -c -o $@ $^
# the test program relies on the file containing main under tests/src and the objects
# link the object files into the executable
$(TEST_TARGET): $(OBJECTS) $(TEST_OBJECTS) $(TEST_MAIN_SOURCE)
@echo "Linking tests..."
$(CC) -o $(TARGETDIR)/$@ $^ $(LIB)
# compile test source files under the subdirectories of tests/src into .o object files
$(TESTDIR)/$(OBJDIR)/%.$(OBJEXT): $(TESTDIR)/$(SRCDIR)/%.$(SRCEXT)
@echo "Compiling tests..."
$(CC) $(CFLAGS_TEST) -c -o $@ $^
# build the tests
test: dirs $(TEST_TARGET)
$(TARGETDIR)/$(TEST_TARGET)
# useful to debug makefile, see what variables eval to
vars:
@echo "CFLAGS: $(CFLAGS)"
@echo "CFLAGS_TEST: $(CFLAGS_TEST)"
@echo "OBJDIR: $(OBJDIR)"
@echo "TESTDIR: $(TESTDIR)"
@echo "SOURCES: $(SOURCES)"
@echo "MAIN_SOURCE: $(MAIN_SOURCE)"
@echo "OBJECTS: $(OBJECTS)"
@echo "TEST_SOURCES: $(TEST_SOURCES)"
@echo "TEST_MAIN_SOURCE: $(TEST_MAIN_SOURCE)"
@echo "TEST_OBJECTS: $(TEST_OBJECTS)"
# remove obj and bin
clean:
@echo "Cleaning..."
rm -rf $(OBJDIR)
rm -rf $(TARGETDIR)
rm -rf $(TESTDIR)/$(TARGETDIR)
rm -rf $(TESTDIR)/$(OBJDIR)
.PHONY: clean
具体来说,我认为这一行:
# compile source files under the subdirectories of src into .o object files
$(OBJDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
@echo "Compiling..."
$(CC) $(CFLAGS) -c -o $@ $^
应该成为bin/obj/list.o
的规则。我知道我的所有文件都存在,包括src/list/list.c
和inc/list.h
。
有谁知道为什么这条规则不满足bin/obj/list.o
?
答案 0 :(得分:0)
https://www.gnu.org/software/make/manual/make.html#index-explicit-rules_002c-secondary-expansion-of表示$^
将扩展为通过$(SRCDIR)/%.$(SRCEXT)找到的每个文件。
我建议重新编写规则,使模式匹配更加明确:
$(OBJDIR)/%.o: $(SRCDIR)/%.c
@echo "Compiling..."
$(CC) $(CFLAGS) -c -o $@ $<
这样你就可以在.c和.o文件之间建立一对一的关系。