6

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.

enter image description here

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$ 
1

2 Answers 2

10

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)
Sign up to request clarification or add additional context in comments.

10 Comments

or $(shell find . -name '*.c')
Thanks for replying --- OBJ := $(patsubst %.c,%.o,$(wildcard /.c)) -- so if i change OBJ as suggested by you then it will search from current directories & the sub-directories ..? .. Also *.o for every file will be created in their respective folders or in main folder ?
One more question --- Is my clean target recipt is correct in this case ?
@Katoch: $(wildcard */*.c) will only search in immediate subdirectories. * never matches /. If you want search across any depth, you need the $(shell find . -name '*.c').
@Katoch: Of course the pattern in clean needs to match the one used to generate list of sources. It is possible to just do rm -f $(OBJ) (it's never -r, the arguments are always files, not directories), but if you delete a source, the object will not get cleaned afterwards. So there is some advantage to having matching pattern. For $(shell find . -name '*.c') the matching command is find . -name '*.o' | xargs rm (you need -f in the former case, because you are passing names that don't exist; you don't need it in the find case where you don't).
|
2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.