Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Post History

60%
+1 −0
Q&A make: How to compile all files in a directory.

Each rule in the Makefile represents a single target. This means that your first makefile has a single target: obj/library.o. I guess that if there is only one target, make assumes that this is the...

posted 7d ago by mr Tsjolder‭  ·  edited 7d ago by Vanity Slug ❤️‭

Answer
#2: Post edited by user avatar Vanity Slug ❤️‭ · 2024-10-11T12:04:54Z (7 days ago)
Original code in answer did not work because it was looking for .c files in current directory. I updated code to look for files in "lib" directory, according how it's spesified in my question.
  • Each rule in the Makefile represents a single target. This means that your first makefile has a single target: `obj/library.o`. I guess that if there is only one target, `make` assumes that this is the target you want to build and does not require targets to be provided by the command line. As a result, your Makefile works "as expected".
  • In the second Makefile your rule has a wildcard and thus represents infinitely many targets. Now `make` is unable to guess what you actually want to build, hence the error. However, you can still use this makefile by providing the targets you want to build on the command line: `make obj/library.o` should provide the exact same results as your initial attempt. If you are only interested in re-building (i.e. all files already exist), you could even use `make obj/*.o` to re-build all files with this Makefile.
  • Your third Makefile introduces the standard target `all`, which is intended to solve the problem with your second makefile: tell `make` which targets to build when no command line arguments are given. The targets provided here are interpreted as literal strings. As a result, the makefile will look for the literal target `%.o`, which does not exist and fail the build.
  • ---
  • Now, if you would look closer at the proposed solution in Stackoverflow, you would notice that the proposed answer does not use any wildcards, but specifies all targets that need to be build. It can be helpful to be explicit about which targets you wish to build (as proposed in the stackoverflow answer), however it is often too convenient to simply use wildcards.
  • Luckily it is possible to use wildcards, but not in the way you might have hoped. Instead of directly specifying a wildcard, you have to create a list of all targets that you wish to build. Because these targets typically won't exist the first time you build the project, you have to somehow generate this list. One way to do that, is by following the [documentation](https://www.gnu.org/software/make/manual/html_node/Wildcard-Function.html), which would lead to the following Makefile:
  • ```
  • DIR_INC=include
  • DIR_LIB=lib
  • DIR_OBJ=obj
  • SOURCES := $(wildcard *.c)
  • OBJECTS := $(patsubst %.c,$(DIR_OBJ)/%.o,$(SOURCES))
  • all: $(OBJECTS)
  • $(DIR_OBJ)/%.o: $(DIR_LIB)/%.c $(DIR_INC)/%.h
  • gcc -c -o $@ $<
  • ```
  • I hope that clears things up for you.
  • Each rule in the Makefile represents a single target. This means that your first makefile has a single target: `obj/library.o`. I guess that if there is only one target, `make` assumes that this is the target you want to build and does not require targets to be provided by the command line. As a result, your Makefile works "as expected".
  • In the second Makefile your rule has a wildcard and thus represents infinitely many targets. Now `make` is unable to guess what you actually want to build, hence the error. However, you can still use this makefile by providing the targets you want to build on the command line: `make obj/library.o` should provide the exact same results as your initial attempt. If you are only interested in re-building (i.e. all files already exist), you could even use `make obj/*.o` to re-build all files with this Makefile.
  • Your third Makefile introduces the standard target `all`, which is intended to solve the problem with your second makefile: tell `make` which targets to build when no command line arguments are given. The targets provided here are interpreted as literal strings. As a result, the makefile will look for the literal target `%.o`, which does not exist and fail the build.
  • ---
  • Now, if you would look closer at the proposed solution in Stackoverflow, you would notice that the proposed answer does not use any wildcards, but specifies all targets that need to be build. It can be helpful to be explicit about which targets you wish to build (as proposed in the stackoverflow answer), however it is often too convenient to simply use wildcards.
  • Luckily it is possible to use wildcards, but not in the way you might have hoped. Instead of directly specifying a wildcard, you have to create a list of all targets that you wish to build. Because these targets typically won't exist the first time you build the project, you have to somehow generate this list. One way to do that, is by following the [documentation](https://www.gnu.org/software/make/manual/html_node/Wildcard-Function.html), which would lead to the following Makefile:
  • ```
  • DIR_INC=include
  • DIR_LIB=lib
  • DIR_OBJ=obj
  • SOURCES := $(wildcard $(DIR_LIB)/*.c)
  • OBJECTS := $(patsubst $(DIR_LIB)/%.c,$(DIR_OBJ)/%.o,$(SOURCES))
  • all: $(OBJECTS)
  • $(DIR_OBJ)/%.o: $(DIR_LIB)/%.c $(DIR_INC)/%.h
  • gcc -c -o $@ $<
  • ```
  • I hope that clears things up for you.
#1: Initial revision by user avatar mr Tsjolder‭ · 2024-10-11T08:26:30Z (7 days ago)
Each rule in the Makefile represents a single target. This means that your first makefile has a single target: `obj/library.o`. I guess that if there is only one target, `make` assumes that this is the target you want to build and does not require targets to be provided by the command line. As a result, your Makefile works "as expected".

In the second Makefile your rule has a wildcard and thus represents infinitely many targets. Now `make` is unable to guess what you actually want to build, hence the error. However, you can still use this makefile by providing the targets you want to build on the command line: `make obj/library.o` should provide the exact same results as your initial attempt. If you are only interested in re-building (i.e. all files already exist), you could even use `make obj/*.o` to re-build all files with this Makefile.

Your third Makefile introduces the standard target `all`, which is intended to solve the problem with your second makefile: tell `make` which targets to build when no command line arguments are given. The targets provided here are interpreted as literal strings. As a result, the makefile will look for the literal target `%.o`, which does not exist and fail the build.

---

Now, if you would look closer at the proposed solution in Stackoverflow, you would notice that the proposed answer does not use any wildcards, but specifies all targets that need to be build. It can be helpful to be explicit about which targets you wish to build (as proposed in the stackoverflow answer), however it is often too convenient to simply use wildcards. 

Luckily it is possible to use wildcards, but not in the way you might have hoped. Instead of directly specifying a wildcard, you have to create a list of all targets that you wish to build. Because these targets typically won't exist the first time you build the project, you have to somehow generate this list. One way to do that, is by following the [documentation](https://www.gnu.org/software/make/manual/html_node/Wildcard-Function.html), which would lead to the following Makefile:
```
DIR_INC=include
DIR_LIB=lib
DIR_OBJ=obj

SOURCES := $(wildcard *.c)
OBJECTS := $(patsubst %.c,$(DIR_OBJ)/%.o,$(SOURCES))

all: $(OBJECTS)

$(DIR_OBJ)/%.o: $(DIR_LIB)/%.c $(DIR_INC)/%.h
	gcc -c -o $@ $<
```

I hope that clears things up for you.