Makefile: there is no rule for creating a goal

I searched for a solution on this site and also tried Google for some time, but for some reason I cannot get it to work.

My source should be in the src directory, and the object files will be in the obj directory. Now I'm trying to create a simple makefie, but I either get an error that there is no rule, or I can not get it to work with directories.

CC = /usr/bin/gcc CXXFLAGS = -O2 -g -Wall -fmessage-length=0 SRC:= nohupshd.cpp \ task.cpp OBJ:= nohupshd.o \ task.o OBJDIR:= obj SRCDIR:= src DEP:= src/task.h LIBS:= TARGET:= nohupshd all: $(TARGET) $(TARGET): $(OBJ) $(CC) -o $(TARGET) $(OBJ) $(LIBS) clean: rm -f $(OBJ) $(TARGET) 

Option 1:

 $(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/ $@ $(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/ $@ 

Option 1a:

 %.o: %.cpp $(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/ $@ $(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/ $@ 

When I use this template, I always get an error that there is no rule for nohupshd.o.

Option 2:

 $(OBJ) : $(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/ $@ $(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/ $@ 

When I use this option, I see that it is trying to build, but I get errors saying that the “.o” file does not match the target pattern.

Another problem is that "$ <" does not give me the source name. For several sites, this should be, but I can see on the output that there is nothing, so how can I fix it?

Update:

In the meantime, my new version looks like this:

 $(OBJDIR)/$(OBJ) : $(OBJDIR)/%.o : $(SRCDIR)/%.cpp $(CC) -S $< -o $(OBJDIR)/`basename $@ .o`.asm $(CC) -c $< -o $@ 

Now it manages to compile the first object file (nohupshd.o), but when make tries to make the second file, it will work again, saying: target 'task.o' does not match the template.

+1
source share
3 answers

So finally, I found the answer on how to write this make file, since the exaplanation of my errors looks at the publication, which I designated as the correct answer:

The resulting make file looks like this, and for completeness I post it here, including the dependencies for the header files (remove the ASM parts if you don't need them):

 .SUFFIXES: .SUFFIXES: .o .cpp .SUFFIXES: .o .d CC := g++ LNK:= ar CXXFLAGS = -O2 -g -Wall -fmessage-length=0 OBJDIR:= obj SRCDIR:= src HDIR:= include INCLUDE_PATHS:= -Iinclude -Iinclude/interfaces -Iinclude/support CPP_FILES := propertyfile/propertyfile.cpp \ propertyfile/propertyitem.cpp \ propertyfile/propertyfactory.cpp OBJ := $(patsubst %.cpp,$(OBJDIR)/%.o, $(CPP_FILES)) SRC := $(patsubst %.cpp,$(SRCDIR)/%.o, $(CPP_FILES)) ASM := $(patsubst %.cpp, $(OBJDIR)/$*.asm, $(CPP_FILES)) LIBS:= TARGET:= libsupport.a all: $(TARGET) $(TARGET): $(OBJ) @echo "Linking..." @$(LNK) rvs $(TARGET) $(OBJ) @cp $(TARGET) ../lib @cp -r include .. clean: rm -f $(OBJ) $(ASM) $(TARGET) -include $(patsubst %.cpp,$(OBJDIR)/%.d, $(CPP_FILES)) $(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(OBJDIR)/%.d @mkdir -p `dirname $@ ` $(CC) $(CXXFLAGS) -S $< -o $(OBJDIR)/$*.asm $(INCLUDE_PATHS) $(CC) $(CXXFLAGS) -c $< -o $@ $(INCLUDE_PATHS) $(OBJDIR)/%.d: $(SRCDIR)/%.cpp $(CC) $(CXXFLAGS) -MM -MT $@ -MF $(OBJDIR)/$*.d -c $< $(INCLUDE_PATHS) 

Hope this helps another user. All the examples that I found were extremely simple and listed several files individually, not part of the rule, but didn’t really explain how it works, or were so complicated that I couldn’t find out how this could help me.

0
source

You actually have a couple if something is wrong.

At first you write My mistake was that I assumed that the% .o pattern matches any pattern ending in .o that doesn't exist; this is not true. A pattern matches any string ending in .o . However, the % character that matches the target side is replaced on the background side with an identical string. Therefore, if you have a target obj/task.o and it matches the %.o pattern, then the trunk (what the manual calls it) will be obj/task , and when the %.c precondition means that make will look for the necessary condition obj/task.c Since it does not exist, and make does not know how to build it, this rule is discarded as not applicable. When writing template rules, you should write them like this, ONLY identical parts of the names correspond to the symbol of the template ( % ). ALL non-identical parts, including catalogs, must be indicated explicitly.

Secondly, the rule $(OBJ) : $(SRC) really wrong. This line says that every object file depends on all the source files, so whenever any one source file changes all , the object files will be recompiled. This is really not what you want (if this is what you want, you do not need to do it: you can just write a simple shell script). I do not know what you mean, because the rules are empty, it calls the template rule; you do not need this to invoke the template rule. The target depends on $(OBJ) , and each object file depends on the source file (due to the template). You do not need this line at all.

Third, I don’t know why you are trying to construct .asm files, and not just compile directly from the source to the object, but if you really want them, it would be cleaner and more “make-like” to create a separate template rule To create them: create a template rule $(OBJDIR)/%.o : $(OBJDIR)/%.asm and a rule $(OBJDIR)/%.asm : $(SRCDIR)/%.c . If you want ASM files to be assembly products, you must declare them as a prerequisite for all or similar, otherwise they will be deleted as intermediate files.

Fourth, the use of things like basename is not required. There are many automatic variables that can be used instead. For example, $* expands to the stem, so you can write $(OBJDIR)/$*.asm . Of course, if you create a separate template rule for ASM files, you can simply use $@ or $< directly. There are also various execution functions that can also be used; see manual.

Fifth, you define a variable containing the header file, DEP , but never use it. Since it is not used, if you modify this file, nothing will be rebuilt. If you know that all source files include every header, you can use $(OBJ) : $(DEP) to determine this; but this means (as in the second paragraph above) that any change to any header forces all objects to recompile. You would be better off automating the creation of prerequisites; since you are using GCC, it is quite simple.

Sixth, you use C ++ files (xxx.cpp), but you use the C compiler. This will not work (the link line will fail: although the compiler can see that you are compiling the C ++ file and doing everything correctly, even if you call gcc when you bind a bunch of objects together, it has no idea C objects or C ++ objects (or FORTRAN or something else), so you MUST use the C ++ interface to communicate, otherwise it won’t pull in the right ones C ++ libraries). You should use the CXX make CXX to build C ++ code, not CC , and set it to g++ not gcc .

Seventh, you do not need .SUFFIXES: .c .o use template rules. They are only needed for suffix rules that you do not have here. You can keep a simple .SUFFIXES: although to disable the built-in pattern matching this is a slight performance improvement.

Finally, you will notice that you really do not need the $(SRC) variable, because make can deduce it from the template rules. However, if you want your makefile to be less burdensome to change, you could build the contents of the OBJ variable from the SRC variable, for example SRC = nohupshd.cpp task.cpp , then OBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(SRC)) .

So, all-in, here is how I would recommend you write your make file (I do not include automatically generated dependencies here):

 .SUFFIXES: CXX := g++ CXXFLAGS := -O2 -g -Wall -fmessage-length=0 OBJDIR := obj SRCDIR := src TARGET := nohupshd SRC := nohupshd.cpp task.cpp DEP := src/task.h LIBS := # ---- OBJ := $(patsubst %.cpp,$(OBJDIR)/%.o,$(SRC)) ASM := $(patsubst %.cpp,$(OBJDIR)/%.asm,$(SRC)) .PHONY: all clean all: $(TARGET) $(ASM) $(TARGET): $(OBJ) $(CXX) -o $@ $^ $(LIBS) clean: rm -f $(OBJDIR)/* $(TARGET) $(OBJDIR)/%.o : $(SRCDIR)/%.asm $(CXX) $(CXXFLAGS) -c -x assembler-with-cpp $< -o $@ $(OBJDIR)/%.asm : $(SRCDIR)/%.cpp $(CXX) $(CPPFLAGS) -S $< -o $@ 
+6
source

Do not repeat directory names on the compiler line. $< and $@ already have directory names.

 $(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(CC) -S $< -o $@ $(CC) -c $< -o $@ 
+1
source

Source: https://habr.com/ru/post/1486391/


All Articles