I have an implicit gnu-makefile side by side with my Cross-platform build file so that I can debug either with the other.
I am trying to keep my architecture constrained such that my builds are implicit in gnu make. This will help restrict any wild build patterns.
I have managed to make everything implicit except for the executable. My makefile is:
CXX=c
CXXFLAGS =-std=c 17
CXXFLAGS =$(shell pkg-config --cflags tesseract)
LDFLAGS =$(shell pkg-config --libs tesseract)
CXXFLAGS =$(shell pkg-config --cflags lept)
LDFLAGS =$(shell pkg-config --libs lept)
main: main.o
ocr-memtest: ocr-memtest.o
However, the last implicit step (the executable) is not linking the standard library (my guess):
in ocr-memtest.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::~basic_string()", referenced from:
_main in ocr-memtest.o
"operator delete[](void*)", referenced from:
_main in ocr-memtest.o
"operator delete(void*)", referenced from:
_main in ocr-memtest.o
"operator new(unsigned long)", referenced from:
_main in ocr-memtest.o
"___gxx_personality_v0", referenced from:
_main in ocr-memtest.o
Dwarf Exception Unwind Info (__eh_frame) in ocr-memtest.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [ocr-memtest] Error 1
With a virtually identical makefile:
CXX=c
CXXFLAGS =-std=c 17
CXXFLAGS =$(shell pkg-config --cflags tesseract)
LDFLAGS =$(shell pkg-config --libs tesseract)
CXXFLAGS =$(shell pkg-config --cflags lept)
LDFLAGS =$(shell pkg-config --libs lept)
main: main.o
ocr-memtest: ocr-memtest.o
$(CXX) -o $@ $< $(CXXFLAGS) $(LDFLAGS) # only change
I am able to compile and run the same code successfully.
The respective compiler output for the two methods on this mac with brew installed packages is:
#implicit, non-working
c -std=c 17 -I/usr/local/Cellar/tesseract/5.0.1/include -I/usr/local/Cellar/leptonica/1.82.0/include/leptonica -I/usr/local/Cellar/leptonica/1.82.0/include/leptonica -c -o ocr-memtest.o ocr-memtest.cpp
cc -L/usr/local/Cellar/tesseract/5.0.1/lib -L/usr/local/Cellar/libarchive/3.5.2/lib -ltesseract -larchive -lcurl -L/usr/local/Cellar/leptonica/1.82.0/lib -llept ocr-memtest.o -o ocr-memtest
# manual, working
c -std=c 17 -I/usr/local/Cellar/tesseract/5.0.1/include -I/usr/local/Cellar/leptonica/1.82.0/include/leptonica -I/usr/local/Cellar/leptonica/1.82.0/include/leptonica -c -o ocr-memtest.o ocr-memtest.cpp
c -o ocr-memtest ocr-memtest.o -std=c 17 -I/usr/local/Cellar/tesseract/5.0.1/include -I/usr/local/Cellar/leptonica/1.82.0/include/leptonica -I/usr/local/Cellar/leptonica/1.82.0/include/leptonica -L/usr/local/Cellar/tesseract/5.0.1/lib -L/usr/local/Cellar/libarchive/3.5.2/lib -ltesseract -larchive -lcurl -L/usr/local/Cellar/leptonica/1.82.0/lib -llept
I suspect I have some misunderstanding that has resulted in me doing something subtly different than expected... How would I configure this make to render the code implicitly all the way to the executable?
CodePudding user response:
There's no way a recipe that only knows the executable name and object file prerequisites can guess what compiler front-end should be used to link: C, C , Fortran, whatever.
You can find the implicit rules via:
make -f/dev/null -p
You'll see that an executable uses this built-in rule:
%: %.o
# recipe to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
Then if you look for LINK.o you'll see:
# default
LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH)
So, the default recipe uses CC.
You can either use:
CC = $(CXX)
Or you can redefine LINK.o:
LINK.o = $(CXX) $(LDFLAGS) $(TARGET_ARCH)
