To compile all C++ files in my source directory I run
g++ -std=c++17 ../src/*.cpp -o ../out/a.out
How can I compile all cpp files in a given directory except for main.cpp?
bash:
shopt -s extglob
g++ -std=c++17 ../src/!(main).cpp -o ../out/a.out
ref: https://www.gnu.org/software/bash/manual/bash.html#Pattern-Matching
for f in $(find /path/to/files -name "*.cpp" ! -name "main.cpp")
do
g++ -std=c++17 path/to/files/"$f" -o /path/to/out/....
done
We can filter the glob into a Bash array:
unset files
for i in ../src/*.cpp
do test "$i" = '../src/main.cpp' || files+=("$i")
done
g++ -std=c++17 "${files[#]}" -o ../out/a.out
Or, using GNU grep and mapfile:
mapfile -d $'\0' -t files < <(printf '%s\0' ../src/*.cpp | grep -zv '/main\.cpp$')
g++ -std=c++17 "${files[#]}" -o ../out/a.out
you can also ls all .cpp files and pipe that into grep -v, to exclude a specific result.
g++ -std=c++17 `ls *.cpp | grep -v main.cpp` -o a.out
Related
I'm just starting out with Make and I have this file:
CODE_FILES := $(shell find . -regextype posix-egrep -regex ".*/[a-z_]*[a-z]\.(cpp|h)")
EXCLUDE := "./bytecode/operators.cpp"
CODE_FILES_COPY = $(filter-out $(EXCLUDE), $(CODE_FILES))
# All nested header files (.h) and source files (.cpp)
# all: a.out
a.out: main.cpp $(CODE_FILES_COPY)
#echo $(EXCLUDE)
#echo $(CODE_FILES_COPY)
#echo $(CODE_FILES)
clang++ main.cpp -o a.out -pthread -std=c++17 -g \
-Wall -Wpedantic -Wextra \
-D DO_CACHE_DECL
# Define: -D PLUMBER_DEBUG -D DO_CACHE_DECL -D TRACKER_DEBUG
./bytecode/operators.out: ./bytecode/operators.cpp
clang++ ./bytecode/operators.cpp -o ./bytecode/operators.out -std=c++17 \
-Wall -Wpedantic -Werror
make clean:
rm -f a.out ./bytecode/operators.out
However, CODE_FILES_COPY and CODE_FILES are exactly the same (a long list of files containing e.g. ./foo/bar/baz.cpp) - the filter-out seems to have not worked. What am I doing wrong in this situation?
I've also probably done some things wrong in the rest of the file, but the focus is on a.out being rebuilt if I modify ./bytecode/operators.cpp which I don't want to happen since it takes a long time to rebuild the whole project and very little time to compile operators.cpp.
You have quotes around "./bytecode/operators.cpp" in your EXCLUDE :=. Remove them and your exclude will match. Your files will not have quotes around them in the list.
Try using
$(info CODE_FILES: $(CODE_FILES))
$(info EXCLUDE: $(EXCLUDE))
to see the difference
I have the following makefile:-
all:
find | grep -E "\.c\$" | xargs gcc -c -I src -I include -w
gcc -o main *.o -lm -pthread
On running make I get the following error:-
find | grep -E "\.c\ | xargs gcc -c -I src -I include -w
/bin/sh: 1: Syntax error: Unterminated quoted string
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 2
I tried answers to similar questions, but adding a SHEBANG line did not help. Also, I have already escaped the $ character. What am I doing wrong here?
make already does most of what you are trying to do. Assuming you aren't expecting find to look recursively in subdirectories, all you really need is
# Rule for building a c file
.c:
gcc -c -I src -I include -w -o $# $<
# Make sure all C files are compiled, then link the resulting object files
all: *.c
gcc -o main *.o -lm -pthread
If you were expecting to find C source files in subdirectories, you might want to restructure your project slightly, by adding Makefiles to each subdirectory and calling make recursively in those directories.
I have the following rules in a Makefile to build an executable in 3 stages:
all: build/myexe
build/myexe: output/main_dats.o output/foo_dats.o | build/
gcc $^ -o $#
output/%.o: output/%.c
patscc -c $< -o $#
output/%_dats.c: src/%.dats | output/
patsopt -cc -o $# -d $<
build/:
mkdir -p build/
output/:
mkdir -p output/
An src/%.dats source file is used to generate an output/%_dats.c source file which is compiled to an output/%.o object file and finally they are linked into the executable build/myexe.
Running make the first time will only successfully build the first of the two .o files:
$ make
mkdir -p output/
patsopt -cc -o output/main_dats.c -d src/main.dats
patscc -c output/main_dats.c -o output/main_dats.o
make: *** No rule to make target `output/foo_dats.o', needed by `build/myexe'. Stop.
rm output/main_dats.c
But running again will build the second .o file and successfully link the executable:
$ make
patsopt -cc -o output/foo_dats.c -d src/foo.dats
patscc -c output/foo_dats.c -o output/foo_dats.o
mkdir -p build/
gcc output/main_dats.o output/foo_dats.o -o build/myexe
rm output/foo_dats.c
and note that at the end of each invocation the command rm output/..._dats.c is deleting the generated .c source file.
Here is a Makefile written without pattern matching:
all: build/myexe
build/myexe: output/main_dats.o output/foo_dats.o | build/
gcc $^ -o $#
output/foo_dats.o: output/foo_dats.c
patscc -c $< -o $#
output/main_dats.o: output/main_dats.c
patscc -c $< -o $#
output/foo_dats.c: src/foo.dats | output/
patsopt -cc -o $# -d $<
output/main_dats.c: src/main.dats | output/
patsopt -cc -o $# -d $<
build/:
mkdir -p build/
output/:
mkdir -p output/
which works more predictably:
$ make
mkdir -p output/
patsopt -cc -o output/main_dats.c -d src/main.dats
patscc -c output/main_dats.c -o output/main_dats.o
patsopt -cc -o output/foo_dats.c -d src/foo.dats
patscc -c output/foo_dats.c -o output/foo_dats.o
mkdir -p build/
gcc output/main_dats.o output/foo_dats.o -o build/myexe
and note that the generated .c files are not being removed any more.
Apparently I am misusing the pattern matching mechanism. I know there is some kind of wildcard function but I believe it is intended for file globbing.
To avoid removing intermediate files, you just need to list them as actual targets somewhere. For example you could write a separate rule:
make_srcs: output/main_dats.c output/foo_dats.c
You don't have to list this target make_srcs as a prerequisite, or provide it a recipe, etc. Just listing the _dats.c files as actual targets or prerequisites in the makefile is enough to keep them from being deleted.
As for your "only building some output" behavior, I don't know: it works fine for me:
$ make --version | head -n1
GNU Make 4.2.1
$ cat Makefile
all: build/myexe
build/myexe: output/main_dats.o output/foo_dats.o | build/
touch $#
output/%.o: output/%.c
touch $#
output/%_dats.c: src/%.dats | output/
touch $#
build/:
mkdir -p build/
output/:
mkdir -p output/
make_srcs: output/main_dats.c output/foo_dats.c
$ rm -rf output build && make
mkdir -p output/
touch output/main_dats.c
touch output/main_dats.o
touch output/foo_dats.c
touch output/foo_dats.o
mkdir -p build/
touch build/myexe
So there's something about your setup which hasn't been made clear in your question. As the comment suggested you need to run make -d (I would leave off the -R option, I don't know why you'd add that) and figure out why make throws that error.
Pattern rules should ideally be deprecated. They are prone to over-matching (because, well, patterns), they can be hard to get working, they bring with them the whole "intermediate target" issue (that's the deletion of output/*.c files that you are observing), they need another dubious feature ("secondary expansion") to make them usable in some more involved scenarios, etc.
In short: using pattern rules is not advised, and using multi-level pattern rules is definitely not advised. Just more trouble than it's worth. IMHO, anyway.
(end rant)
So I suggest that you write a simple macro instead, so your makefile ends up looking like this:
all: build/myexe
# $(call dats,basename)
define dats
output/$1_dats.o: output/$1_dats.c
patscc -c $$< -o $$#
output/$1_dats.c: src/$1.c | output
patcc -cc -o $$# -d $$<
endif
build/myexe: output/main_dats.o output/foo_dats.o | build
gcc $^ -o $#
$(eval $(call dats,foo))
$(eval $(call dats,main))
build:
mkdir -p build
output:
mkdir -p output
Hi I've a question about feeding inputs to this simple bash script I wrote. All it does is add a set of flags to my compile operation to save me having to write them in myself every time. I can run it by using echo myprogram.c -o myprogram -llibrary | ./Compile.
But I can't find a way to run it in the way I expected to be able to, ./Compile < myprogram.c -o myprogram -llibrary
I've tried a few combinations of quotes and brackets to no avail, can anyone tell me how to feed the same input as produced by echo using the redirect input command.
#!/bin/bash
# File name Compile
#Shortcut to compile with all the required flags, name defaulting to
#first input ending in .c
echo "Enter inputs: "
read inputs
gcc -Wall -W -pedantic -std=c89 -g -O $inputs
exit 0
Just change your shell to:
#!/bin/bash
gcc -Wall -W -pedantic -std=c89 -g -O "$#"
Then you can only write(no redirection needed):
./Compile myprogram.c -o myprogram -llibrary
BTW, don't explicitly write exit 0 at end of this shell. It is redundant when gcc succeeds, and is wrong when gcc fails(exit code 1 will be overwritten).
You can use process substitution:
./Compile < <( echo myprogram.c -o myprogram -llibrary )
the above line produces the same result as your original command:
echo myprogram.c -o myprogram -llibrary | ./Compile
I am looking at a Makefile written by someone else and I see that (after variable expansion) he calls gcc with a sequential list of -L paths followed by -l libraries.
For example:
gcc file.o -Lpath_1 -la -lb -c -Lpath_2 -ld -le -lf ... -o binary_file
My questions are:
Does this call guarantee that gcc:
only looks into path1 when searching for -la, -lb and -lc,
and only looks into path2 when searching for -ld, -le, and -lf?
Is this "proper" (recommended) gcc syntax?