Home > Blockchain >  How does one implicitly compile a C executable using GNU-Make?
How does one implicitly compile a C executable using GNU-Make?

Time:01-29

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)
  •  Tags:  
  • Related