Reputation: 2777
To compile two files i have created a makefile where i use to mention the object name or i can use the pattern rule using patsubst.
# ----------------------------------------------------------------------------
# Makefile for building tapp
#
# Copyright 2010 FriendlyARM (http://www.arm9.net/)
#
ifndef DESTDIR
DESTDIR ?= /opt/FriendlyARM/tiny6410/linux/rootfs_qtopia_qt4
endif
#CFLAGS = -c -Wall -O2 # wall is for warning show and 02 is optiminisation level 2
CFLAGS = -c -O2 # wall is for warning show and 02 is optiminisation level 2
#CC = arm-linux-gcc # compiler name
CC = gcc # compiler name
LD = ld
INSTALL = install #
TARGET = led_player_project
#OBJ = led-player_backup.o led-player.o
OBJ := $(patsubst %.c,%.o,$(wildcard *.c */*.c))
#OBJ = $(shell find . -name '*.c')
all: $(TARGET)
#all: $(OBJ)
led_player_project : $(OBJ)
$(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
# $(LD) $(LDFLAGS) -o $@ $< $(LIBS)
%.o : %.c
$(CC) $(CFLAGS) $< -o $@
#$< -o $@
install: $(TARGET)
$(INSTALL) $^ $(DESTDIR)/usr/bin
clean :
rm -rf *.o $(TARGET) $(OBJ)
# ----------------------------------------------------------------------------
.PHONY: $(PHONY) install clean
# End of file
# vim: syntax=make
#EOF
Now if my project contains folder contains subfolders & they contains further files. Then can i write pattern rule to compile every file & create an common executable?
1> Do i will have to create makefile in every-subfolder so that i can invoke that makefile from main makefile, like integrating static driver to linux kernel each driver have respective makefile ?
2> Or common makefile for full project ?
3> can i use patsubst to compile every file without mentioning there name.
4> How can i combine every *.o to create on executable called main
.
Edit :---
@Jan Hudec
I have modified my makefile as per your comment (i have posted it above). Now i am just trying with two folders inside my main folder. I am getting following error
Folder structure :--
main Folder ----> one Folder
----> two Folder
Folder Main contains :--
main.c
main.h
Makefile
Folder one contains :--
one.c
one.h
Folder two contains :--
two.c
two.h
main.c content :--
#include <stdio.h>
#include <stdlib.h>
#include "main.h"
int main()
{
char *p;
printf("\n\n main \n");
one();
two();
return 0;
}
main.h content :---
#include "one/one.h"
#include "two/two.h"
one.c content :---
#include <stdio.h>
#include <stdlib.h>
#include "one.h"
void one()
{
printf("\n one \n");
}
one.h content :---
void one();
two.c content :---
#include <stdio.h>
#include <stdlib.h>
#include "two.h"
void two()
{
printf("\n two \n");
}
two.h content :---
void two();
Error i got at make time :----
ignite@ignite:~/testing/main$ make
gcc -c -O2 main.c -o main.o
gcc -c -O2 one/one.c -o one/one.o
gcc -c -O2 two/two.c -o two/two.o
ld -o led_player_project main.o one/one.o two/two.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048080
main.o: In function `main':
main.c:(.text.startup+0x11): undefined reference to `puts'
one/one.o: In function `one':
one.c:(.text+0xb): undefined reference to `puts'
two/two.o: In function `two':
two.c:(.text+0xb): undefined reference to `puts'
make: *** [led_player_project] Error 1
ignite@ignite:~/testing/main$
Upvotes: 6
Views: 23089
Reputation: 31
Perhaps another solution too. I have a source directory in my project dir which contains subdirectories. And I dont want have a Makefile in every subdirectories or something else. And I want to build everything only with one makefile in rootdir of project: So for my static library in c++ i did this makefile. Perhaps it could be a solution for you too. But I didnt test it well with paralell builds via "make -j4" or so.
BUILDCXX=g++-10
CHECKCXX=clang++-12
CXXFLAGS=-std=c++17 -Wall -Werror -Wextra -g -pg -O0 -I. -DDEBUG
CXXFLREL=-std=c++17 -Wall -Werror -Wextra -O3 -s -I. -DNDEBUG
CXXFLAGSLIB=$(CXXFLAGS)
CXXFLAGSTST=$(CXXFLAGS) -DRLOG_COMPONENT="clbc"
LDFLAGS=
LDFLAGSLIB=$(LDFLAGS)
LDFLAGSTST=$(LDFLAGS) -L./target/lib -lUnitTest++ -lclbc
OUTDIR=target
OUTDIRLIB=$(OUTDIR)/lib
OUTDIRTST=$(OUTDIR)/bin
OUTDIROBJ=$(OUTDIR)/obj
OUTFILELIB=libclbc.a
OUTFILETST=runtests
SRCDIR=source
SRCDIRLIB=$(SRCDIR)/lib
SRCDIRTST=$(SRCDIR)/test
SRCDIRSLIBR := $(shell find $(SRCDIRLIB) -maxdepth 3 -type d)
SRCFILESLIB := $(foreach dir,$(SRCDIRSLIBR),$(wildcard $(dir)/*.cpp))
OBJFILESLIB := $(addprefix $(OUTDIROBJ)/,$(notdir $(patsubst %.cpp,%.o,$(SRCFILESLIB))))
SRCDIRSTSTR := $(shell find $(SRCDIRTST) -maxdepth 3 -type d)
SRCFILESTST := $(foreach dir,$(SRCDIRSTSTR),$(wildcard $(dir)/*.cpp))
OBJFILESTST := $(addprefix $(OUTDIROBJ)/,$(notdir $(patsubst %.cpp,%.o,$(SRCFILESTST))))
.PHONY: all
all: clean lib
check-syntax:
$(CHECKCXX) $(CXXFLAGS) -s -o /dev/null -S $(CHK_SOURCES)
clean:
@rm -rf $(OUTDIR)
lib:$(OBJFILESLIB)
@mkdir -p $(OUTDIRLIB)
@echo " TargetLib :" $(OUTDIRLIB)/$(OUTFILELIB)
@ ar rcs $(OUTDIRLIB)/$(OUTFILELIB) $^
test:$(OBJFILESTST)
@mkdir -p $(OUTDIRTST)
@echo "TargetTest :" $(OUTDIRTST)/$(OUTFILETST)
@ $(BUILDCXX) $(OBJFILESTST) -o $(OUTDIRTST)/$(OUTFILETST) $(LDFLAGSTST)
release: CXXFLAGSLIB=$(CXXFLREL)
release:$(OBJFILESLIB)
@mkdir -p $(OUTDIRLIB)
@echo "RTargetLib :" $(OUTDIRLIB)/$(OUTFILELIB)
@ ar rcs $(OUTDIRLIB)/$(OUTFILELIB) $^
define set_real_src_file
$(eval REAL_SRC_FILE=$(strip $(1)))
endef
define set_nothing
endef
define get_real_src_file
$(if $(strip $(findstring $(strip $(1)),$(strip $(2)))),$(call set_real_src_file,$(2)),$(call set_nothing))
endef
define get_source_file
@echo ObjectFile : $(1)
$(eval REAL_SRC_SEARCH=$(notdir $(patsubst %.o,%.cpp,$(1))))
$(eval REAL_SRC_FILE=)
$(foreach word,$(2), $(call get_real_src_file, $(REAL_SRC_SEARCH),$(word)))
endef
$(OBJFILESLIB): $(SRCFILESLIB)
@mkdir -p $(OUTDIROBJ)
$(call get_source_file,$@,$^,$<)
@ $(BUILDCXX) $(CXXFLAGSLIB) -c $(REAL_SRC_FILE) -o $@
$(OBJFILESTST): $(SRCFILESTST)
@mkdir -p $(OUTDIROBJ)
$(call get_source_file,$@,$^,$<)
@ $(BUILDCXX) $(CXXFLAGSTST) -c $(REAL_SRC_FILE) -o $@
But I guess it runs only with GNUMake and no other implementations of make.
Upvotes: 2
Reputation: 76246
Ad 1 and 2: The filenames can safely include directories and %
matches /
as necessary. So you can easily have:
$(wildcard subdir/*.c) $(wildcard anotherdir/*.c)
or even
$(wildcard */*.c)
... or as suggested by keltar in comment
$(shell find . -name '*.c')
which is recursive.
Ad 3: You are doing it.
Ad 4: Create a target with $(OBJ)
as dependencies and use the automatic variable just as you do for compilation:
main : $(OBJ)
$(LD) $(LDFLAGS) -o $@ $< $(LIBS)
Upvotes: 10