如何使用 GNU-Make 隐式编译 C++ 可执行文件?

How does one implicitly compile a C++ executable using GNU-Make?

我有一个隐式 gnu-makefile 与我的跨平台构建文件并排放置,以便我可以与另一个一起调试。

我试图限制我的架构,这样我的构建就隐含在 gnu make 中。这将有助于限制任何野生构建模式。

除了可执行文件之外,我已经设法使所有内容都隐含了。我的 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

但是,最后一个隐式步骤(可执行文件)没有链接标准库(我的猜测):

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

使用几乎相同的 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

我能够成功编译 运行 相同的代码。


在这个 mac 上使用 brew 安装包的两种方法各自的编译器输出是:

#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

我怀疑 我有一些误解 导致我做了一些与预期略有不同的事情...我将如何配置此 make 以隐式呈现代码一直到可执行文件?

只有知道可执行文件名称和目标文件先决条件的方法才能猜出应该使用什么编译器 front-end link:C、C++、Fortran 等等。

您可以通过以下方式找到隐式规则:

make -f/dev/null -p

您会看到可执行文件使用此 built-in 规则:

%: %.o
#  recipe to execute (built-in):
        $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@

然后,如果您查找 LINK.o,您会看到:

# default
LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH)

因此,默认配方使用 CC

您可以使用:

CC = $(CXX)

或者你可以重新定义LINK.o:

LINK.o = $(CXX) $(LDFLAGS) $(TARGET_ARCH)