I'm trying to use precompiled headers for the first time. I have the following rules in my Makefile:
$(UNITS_h_gch): $(builddir)/%.h.gch: $(INCLUDEDIR)/%.h $(mk) \
| $$(#D)/. $(builddir)/%.h.d
$(info - CC $$builddir/$*.h.gch)
$(CC) $(CFLAGS) -I $(INCLUDEDIR) -DPCH -S -o $# $<
$(UNITS_c_s): $(builddir)/%.c.s: $(SRCDIR)/%.c $(builddir)/alx/%.h.gch $(mk) \
| $$(#D)/. $(builddir)/%.c.d
$(info - CC $$builddir/$*.c.s)
$(CC) $(CFLAGS) -I $(builddir) -I $(INCLUDEDIR) -S -o $# $<
The rule for the .s files is the same as before, except that it now depends also on the PCH, obviously; and also that it includes $(builddir) in the headers with -I to be able to use the precompiled headers that I generate there.
The nonstandard notation (.c.s) is to simplify the Makefile, as I also have .cxx.s files which follow a slightly different rule, using g++ of course.
As GCC documentation says (https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html), I used the same command line to produce the PCHs. It failed due to #pragma once, so I added a conditional in the headers to remove it when building the PCH; that's why I define PCH with -DPCH.
I've seen that people compiles PCHs with -c, but I also produce temporary assembly files, so I used -S. May that be the cause f the failure?
Logs:
$ make
- CC $builddir/alx/base/assert/array.h.gch
- CC $builddir/base/assert/array.c.s
/home/alx/src/alx/libalx/src/base/assert/array.c:10:35: error: /home/alx/src/alx/libalx/tmp/alx/base/assert/array.h.gch: not a PCH file [-Werror]
10 | #include <alx/base/assert/array.h>
| ^
cc1: all warnings being treated as errors
make[1]: *** [/home/alx/src/alx/libalx/lib/recipes.inc.mk:49: /home/alx/src/alx/libalx/tmp/base/assert/array.c.s] Error 1
make: *** [Makefile:63: base] Error 2
I'm seeing an error because of -Werror, and that appeared after adding -Winvalid-pch. Before that the compilation was successful, but because it was taking the original header file, and not the precompiled one. I suspected of this, because the compilation was twice as slow.
BTW, I use bracket includes (<...>) because this is a library that I install in the system and then use from other programs.
Related
Automate the compilation of auto-generated C files with regular C files
We have developed a program "cperformer" that is able to generate a C file from a text file (to keep it simple).
It is a kind of "meta-compiler" that generates C file as output. Thus, we would like to improve the usage of this "C generator" by automating the generation of each C file as a first step of a makefile, and then compile and link together all of these generated C files with other C files already present with GCC in the same makefile.
Makefile 1
C_GEN :=./cperformer -n
CC :=gcc
CFLAGS :=-I.
#List all .c files generated from .text files
AUTO_SRCS = $(wildcard *.text)
AUTO_OBJS_C := $(patsubst %.text,%_alg.c,$(AUTO_SRCS))
$(info *INFO* Text files = $(AUTO_SRCS))
#List all .c files to compile (auto-generated or not)
SRCS = $(AUTO_OBJS_C)
SRCS += $(wildcard *.c)
OBJS := $(patsubst %.c,%.o,$(SRCS))
$(info *INFO* C files = $(SRCS))
# Main target rule
target : $(OBJS)
$(CC) -o $# $(OBJS) $(CFLAGS)
# Pre-compilation step (some C files generation)
prelim $(AUTO_OBJS_C): $(AUTO_SRCS)
$(C_GEN) $<
# Pre-compilation step (object files generation)
%.o: %.c
$(CC) -c -o $# $< $(CFLAGS)
all: prelim target
clean :
rm -f TARGET $(OBJS) *_alg*
Error 1
$ make all
*INFO* Text files = file3.text file2.text file1.text
*INFO* C files = file3_alg.c file2_alg.c file1_alg.c linked_list.c main.c
./cperformer -n file3.text
Compiling: file3.text ...
No error.
Done.
gcc -c -o file3_alg.o file3_alg.c -I.
./cperformer -n file3.text
Compiling: file3.text ...
No error.
Done.
gcc -c -o file2_alg.o file2_alg.c -I.
gcc: error: file2_alg.c: No such file or directory
gcc: fatal error: no input files
compilation terminated.
make: *** [Makefile:29: file2_alg.o] Error 1
It fails because the "cperformer" program is asked to generate the same C file each time "file3.c" so GCC don't find "file2.c" as expected and it aborts the compilation.
Makefile 2
Replace the C generative rule of the above makefile with the use of "%" :
# Pre-compilation step (some C files generation)
%.c: %.text
$(C_GEN) $<
Error 2
make: *** No rule to make target 'file3_alg.o', needed by 'target'. Stop.
Nothing compiles here.
Makefile 3
The dirty fix
batch_c_generation :
#$(foreach TXT_FILE, $(AUTO_SRCS), $(C_GEN) $(TXT_FILE);)
This is kind of working but remains very dirty because it re-generates all C files at each build and some duplication errors appear when it is not properly cleared between each make.
How can I fix the makefile ?
You were close -- simply fix your pattern rule to look like this:
%_alg.c : %.text
$(C_GEN) $<
As #tripleee mentioned, the reason your makefile1 rule failed was that it expands to something like:
file2_alg.c file1_alg.c: file2.text file1.text
$(CGEN) $<
In this case $< expands to the first dependency which will always be file2.text...
In your makefile2 example, you used %.c instead of %_alg.c (and hence there's no rule to build file2_alg.c, and therefore no rule to build file2_alg.o)
I'm using GNU make and have the following in my Makefile:
token_check: token_check.o $(STATIC_LIBRARIES)
$(CC) -o $# $^
%.o: %.c pipeline/*.h compiler/*.h
$(CC) $(COMPILER_FLAGS) -I./pipeline -I./compiler -c $<
However, when I run make, the command actually run is
cc -c -o token_check.o token_check.c
and I get the error
token_check.c:3:10: fatal error: scanner.h: No such file or directory
3 | #include "scanner.h"
| ^~~~~~~~~~~
compilation terminated.
make: *** [<builtin>: token_check.o] Error 1
scanner.h is contained in the compiler subdirectory.
Why are my -I directives being ignored?
EDIT:
I checked and I do have header files in both pipeline and compiler.
What's really weird is, even if I replace the recipe with
%.o: %.c pipeline/*.h compiler/*.h
echo blah
and run
make token_check.o
it still tries to compile the source file and "blah" never gets printed.
Most likely make is using its implicit rule, not yours. And most likely it does so because your pattern rule does not apply. One reason could be that you do not have any header file in pipeline.
I'm on a Windows machine and use MinGW, attempting to compile a hello world program that uses a shared library. After an absurd amount of attempts, I found out the following:
Manually compiling it with gcc and providing -I and -L flags for the required directories works fine.
Using the msys make.exe file provided under the MinGW/msys/1.0/bin installation directory properly executes a Makefile with no problems
Using the mingw32-make.exe provided under MinGW/bin doesn't work properly when trying to build using the same Makefile. From my understanding, it doesn't parse the -I and -L flags at all. It works fine if I add the dependencies (both includes and libs) under their respective MinGW directories.
These past few days while I was trying and familiarizing myself with these tools (I'm comfortable with C's syntax but know about nothing past that) I read many guides and no one seemed to have this issue (from the few that actually attempted this on a Windows machine without using an IDE). Did I miss something? Is my MinGW installation known to have this issue?
Note that at first I was attempting to compile the project using the 64-bit version of the library but failed. I'm guessing this means that I have a 32-bit MinGW installation.
Knowing that some will ask to see the Makefile:
CC = gcc
MY_LIB = -L/e/C_Projects/Libraries/MySharedLib/lib -lMyLibName
MY_INCLUDE = -I/e/C_Projects/Libraries/MySharedLib/include
CFLAGS = -Wall -c $(MY_INCLUDE)
LDFLAGS = -lmingw32 -mwindows $(MY_LIB)
EXE = Test.exe
all: $(EXE)
$(EXE): main.o
$(CC) $< $(LDFLAGS) -o $#
main.o: main.c
$(CC) $(CFLAGS) $< -o $#
clean:
del *.o && del $(EXE)
The error produced by mingw32-make.exe is the following
main.c:1:22: fatal error: MyLib.h: No such file or directory
#include <MyLib.h>
^
compilation terminated.
Makefile:19: recipe for target 'main.o' failed
mingw32-make: *** [main.o] Error 1
I'm trying to compile a c-file with dependencies, using a makefile that gets stuck with this error:
Compiling tpc_lqe.o ...
/cygdrive/c/Sandbox/ZigBee/Tools/ba-elf-ba2/bin/ba-elf-gcc -c -o tpc_lqe.o
[some -options]
-I/cygdrive/c/Sandbox/ZigBee/Components/TPC/Include
-I/cygdrive/c/Sandbox/ZigBee/Components/TPC/Source
-I/cygdrive/c/Sandbox/ZigBee/Components/AppApi/Include
-I/cygdrive/c/Sandbox/ZigBee/Components/Common/Include
-I /cygdrive/c/Sandbox/ZigBee/Components/TPC/Source/tpc_lqe.c -MD -MF tpc_lqe.d -MP
ba-elf-gcc: no input files
make: *** [tpc_lqe.o] Error 1
Makefile:138: recipe for target 'tpc_lqe.o' failed
I saw other questions regarding the same error, but I can't relate to them with my problem.
This is the makefile line that is causing the error, please point out if some context is missing:
%.o: %.c
$(info Compiling $# ...)
$(CC) -c -o $*.o $(CFLAGS) $(INCFLAGS) $< -MD -MF $*.d -MP
Update following unwind's answer:
I didn't include specify a variable (include path of a library), which caused the following inclusion of that variable (INCFLAGS) to contain a blank space in its stead. This blank space ended up in the -I option thus returning the error.
Once defined that variable, everything worked smoothly.
INCFLAGS looks broken, since the compiler invocation has a "bare" -I, without a value immediately following, which causes gcc to interpret the next argument (the source file name) as that argument:
[...] -I /cygdrive/c/Sandbox/ZigBee/Components/TPC/Source/tpc_lqe.c
^
|
???
#compile time flags
CFLAGS=-Wall -Werror
CC=gcc
all: prog-1-gcc prog-2-gcc prog-3-gcc prog-4-gcc prog-5-gcc prog-6-gcc \
prog-7-gcc prog-8-gcc prog-9-gcc prog-10-gcc prog-11-gcc prog-12-gcc \
prog-13-gcc prog-14-gcc prog-15-gcc prog-16-gcc prog-17-gcc prog-18-gcc \
prog-19-gcc prog-20-gcc prog-21-gcc
all-gcc: all
run: run-1-gcc run-2-gcc run-3-gcc run-4-gcc run-5-gcc run-6-gcc \
run-7-gcc run-8-gcc run-9-gcc run-10-gcc run-11-gcc \
run-12-gcc run-13-gcc run-14-gcc run-15-gcc run-16-gcc \
run-17-gcc run-18-gcc run-19-gcc run-20-gcc run-21-gcc
run-gcc: run
prog-%-gcc: prog-%.c
$(CC) $(CFLAGS) $< -o prog-$*.out
run-%-gcc: prog-%.out
-./prog-$*.out
make clean:
rm -f all *.out
This makefile gives me this error on solaris9 machine when i type
bash-2.05$ make prog-9-gcc
make: Fatal error: Don't know how to make target `prog-9-gcc'
This happens with all rules including the make clean rule. I would appreciate anyone's input as i have been stuck with this bug for a few days now thanks!I should also probably mention this makefile runs 100% perfectly on a centos machine.
Question: What can i do to my make file or my input line on solaris to make this work when compiling and running my C Files.
Answered Below in the comments by Charlie Burns
This rule tells make it can build prog-9-gcc from a file prog-9.c. So, if make is giving that error it means that there's no file proc-9.c in your directory:
prog-%-gcc: prog-%.c
gcc $(CFLAGS) prog-$*.c -o prog-$*.out
The other problem with this rule is that it tells make it will build a file prog-%-gcc (for some value of %) but it's lying. It actually builds a totally different file, prog-%.out. Because of this, make will rebuild all the targets every time you run make. This rule should read:
prog-%-gcc: prog-%.c
gcc $(CFLAGS) $< -o $#
Really you should set CC = gcc and use $(CC) in the rule.