creating my own automake script

Programming, for all ages and all languages.
Post Reply
dudeman
Posts: 21
Joined: Tue Jan 15, 2008 12:30 pm

creating my own automake script

Post by dudeman »

In school our teachers use Windows and an IDE to write all the little C++ console apps we do. I'm using linux, and no fancy IDE, so I'd like to automate things for myself a bit.

Here is a generic Makefile I have where I only have to edit my SOUCES list and the EXECUTABLE name of my prog.:

Code: Select all

CC=g++
CFLAGS=-c -Wall -Wextra -pedantic
LDFLAGS=
SOURCES=sourceFile.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=progName

all: $(SOURCES) $(EXECUTABLE)
	
$(EXECUTABLE): $(OBJECTS) 
	$(CC) $(LDFLAGS) $(OBJECTS) -o $@

.cpp.o:
	$(CC) $(CFLAGS) $< -o $@
	
clean:
	rm -rf *o $(EXECUTABLE)
I'd like to create a bash-script that will do the following things for me:

1. Copy my Makefile to my current working dir.
2. Either prompt me for my sources list or auto-find them and edit the above Makefile to include them on the SOURCES= line.
and
3. Prompt me for the EXECUTABLE name and likewise, edit the Makefile to
include on the EXECUTABLE= line.

I'm very new to linux, and even newer to shell-scripting. Any ideas, suggestions are welcome!

P.S. I read Solar's Makefile tutorial and well, there wasn't much I understood in there! Don't laugh at my feeble-minded attempt here!
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

Code: Select all

#!/bin/bash

sources=`find ./ -name *.c`

echo "
CC=g++
CFLAGS=-c -Wall -Wextra -pedantic
LDFLAGS=
SOURCES=$sources
OBJECTS=\$(SOURCES:.cpp=.o)
EXECUTABLE=$1

all: \$(SOURCES) \$(OBJECTS) -o \$@

.cpp.o:
        \$(CC) \$(CFLAGS) \$< -o \$@

clean:
        rm -rf *.o \$(EXECUTABLE)" > Makefile
Run it in the directory you want the makefile to be created in. Give it one parameter - the name of the executable. It will auto find any .c files inthe current directory (and by default recursing through all subdirectories).

E.g.

Code: Select all

./test.sh myExecutable
Produces the makefile:

Code: Select all

[17:14:04] ~/pedigree_test $ cat Makefile

CC=g++
CFLAGS=-c -Wall -Wextra -pedantic
LDFLAGS=
SOURCES=./test.c
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=Myexec

all: $(SOURCES) $(OBJECTS) -o $@

.cpp.o:
        $(CC) $(CFLAGS) $< -o $@

clean:
        rm -rf *.o $(EXECUTABLE)
Cheers,

James
dudeman
Posts: 21
Joined: Tue Jan 15, 2008 12:30 pm

Post by dudeman »

Thanks for your help. The script still has one minor problem that I can't seem to figure out. Using this script:

Code: Select all

#!/bin/bash

sources=`find *.c*`

echo "
CC=g++
CFLAGS=-c -Wall -Wextra -pedantic
LDFLAGS=
SOURCES=$sources
OBJECTS=\$(SOURCES:.cpp=.o)
EXECUTABLE=$1

all: \$(SOURCES) \$(EXECUTABLE)

\$(EXECUTABLE): \$(OBJECTS)
	\$(CC) \$(LDFLAGS) \$(OBJECTS) -o \$@

.cpp.o:
	\$(CC) \$(CFLAGS) \$< -o \$@

clean:
	rm -rf *.o \$(EXECUTABLE)" > Makefile
It separates my sources on multiple lines like so:

Code: Select all

SOURCES=src1.c
src2.c
src3.c
#etc, etc, etc.
Which, when "make" is called, complains that it's missing a separator.

Is there a way I can modify "find" to print them all on the same line separated only by a single space?
User avatar
B.E
Member
Member
Posts: 275
Joined: Sat Oct 21, 2006 5:29 pm
Location: Brisbane Australia
Contact:

Post by B.E »

try this:

Code: Select all

#!/bin/bash

sources=`find . -name '*.c' -printf '%p '`

echo "
CC=g++
CFLAGS=-c -Wall -Wextra -pedantic
LDFLAGS=
SOURCES=$sources
OBJECTS=\$(SOURCES:.cpp=.o)
EXECUTABLE=$1

all: \$(SOURCES) \$(EXECUTABLE)

\$(EXECUTABLE): \$(OBJECTS)
   \$(CC) \$(LDFLAGS) \$(OBJECTS) -o \$@

.cpp.o:
   \$(CC) \$(CFLAGS) \$< -o \$@

clean:
   rm -rf *.o \$(EXECUTABLE)" > Makefile
Image
Microsoft: "let everyone run after us. We'll just INNOV~1"
dudeman
Posts: 21
Joined: Tue Jan 15, 2008 12:30 pm

Post by dudeman »

hey that works perfectly!

mucho gracias!
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post by Solar »

P.S. I read Solar's Makefile tutorial and well, there wasn't much I understood in there!
Perhaps we could work together - you pointing out what you did not understand, and me improving the tutorial?

The idea to have a script working around lacks of understanding of Makefile syntax is understandable, but if I were you, I'd try to understand rather than work around. What you wrote a script for, 'make' can do itself!

Getting all *.c files in a list:

Code: Select all

SOURCES := $(shell find . -name "*.c")
Getting the corresponding *.o filenames:

Code: Select all

OBJECTS := $(patsubst %.c,%.o,$(SOURCES))
And if the current directory's name is good enough for you as executable name, that can be done too:

Code: Select all

EXECUTABLE := $(notdir $(shell pwd))
If you want to get the commands explained ($shell, $patsubst, $notdir), they're in 'info make'.

A number of other flaws of your Makefile:
  • Use := instead of =, so the commands get executed once, instead of everytime the variable is used.
  • $(CC) is the C compiler. If you want the C++ compiler, use $(CXX) (and $(CXXFLAGS). Then you might want to find *.cpp files instead of *.c ones, too...
  • -c should be part of the rule, not part of CFLAGS.
  • Your 'all' rule does too much.
  • Your "clean" rule would delete any file ending in o, not only *.o...
Your original Makefile, including my suggestions and the dependency handling from the tutorial, assuming C compilation:

Code: Select all

CFLAGS := -Wall -Wextra -pedantic -Wshadow -Wpointer-arith -Wcast-align \
          -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations \
          -Wredundant-decls -Wnested-externs -Winline -Wno-long-long \
          -Wconversion -Wstrict-prototypes
LDFLAGS :=
SOURCES := $(shell find . -name "*.c")
OBJECTS := $(patsubst %.c,%.o,$(SOURCES))
DEPENDENCIES := $(patsubst %.c,%.d,$(SOURCES))
EXECUTABLE := $(notdir $(shell pwd))

all: $(EXECUTABLE) 
    
$(EXECUTABLE): $(OBJECTS) 
   $(CC) $(LDFLAGS) $(OBJECTS) -o $@ 

-include $(DEPENDENCIES)

%.o: %.cpp 
   $(CC) $(CFLAGS) -MMD -MP -MT "$*.d" -c $< -o $@ 

clean: 
   rm -rf *.o $(EXECUTABLE)
Not tested on your source tree, no guarantees given.
Every good solution is obvious once you've found it.
dudeman
Posts: 21
Joined: Tue Jan 15, 2008 12:30 pm

Post by dudeman »

wow, that's pretty slick Solar!

As far as what I didn't understand from your tutorial:

I suppose it was mostly that "Make Syntax" you mentioned in your reply.

It's not that your tutorial is flawed in some manner, it's my elementary understanding of Makefiles that made the whole thing whiz by, far above my head. I shall take your advice though, and study Makefiles intently now. Remember, I'm quite new to doing anything in Linux, and my new reality includes Makefiles. There's no two ways around it now, so I shall conquer, in due time...
dudeman
Posts: 21
Joined: Tue Jan 15, 2008 12:30 pm

Post by dudeman »

I'm afraid to ask this next question...

would it be bad to write a script simply to copy the makefile to my current directory?
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post by Solar »

There's nothing "bad", but why would you want to write a script for what is a simple file copy?

Edit: Ieek, I forgot the .PHONY part:

Code: Select all

.PHONY: all clean
Without that, your "all" and "clean" rules would refuse to execute if there were files named "all" or "clean" present in the work directory.
Every good solution is obvious once you've found it.
Post Reply