Page 1 of 1

creating my own automake script

Posted: Thu Jan 24, 2008 10:14 am
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!

Posted: Thu Jan 24, 2008 11:16 am
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

Posted: Fri Jan 25, 2008 12:48 pm
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?

Posted: Sat Jan 26, 2008 1:48 am
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

Posted: Sun Jan 27, 2008 1:31 pm
by dudeman
hey that works perfectly!

mucho gracias!

Posted: Tue Jan 29, 2008 7:04 am
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.

Posted: Tue Jan 29, 2008 10:25 am
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...

Posted: Tue Jan 29, 2008 10:34 am
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?

Posted: Wed Jan 30, 2008 1:32 am
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.