Makefile не видит main.o один раз из двух

#c #macos #build #makefile #clang

#c #macos #сборка #makefile #clang

Вопрос:

Хорошо, я пытаюсь создать makefile для компиляции программы в разных средах. В Linux (Mint) это работает просто отлично, но в Mac OS я получаю эту ошибку:

 Undefined symbols for architecture x86_64:
  "_main", referenced from:
     implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [build] Error 1
 

С помощью ‘-v’:

 Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.1.0
Thread model: posix
 "/Library/Developer/CommandLineTools/usr/bin/ld" -demangle -dynamic -arch x86_64 -macosx_version_min 10.9.0 -w -o bin/Darwin/main ./cfprintf.o ./file.o ./inputmanager.o ./neditfile.o ./neditmanager.o ./neditscreen.o ./n_string.o ./sys_booter.o ./sys_display.o ./sys_manager.o ./sys_screen.o -lc   -lSystem /Library/Developer/CommandLineTools/usr/bin/../lib/clang/5.1/lib/darwin/libclang_rt.osx.a
Undefined symbols for architecture x86_64:
  "_main", referenced from:
     implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [build] Error 1
 

Теперь вот makefile:

 CC = clang  
LIB = 
INC = -I src/
OPTIONS = -w

OBJS = $(shell find ./src/obj -name '*.cpp')
IO = $(shell find ./src/io -name '*.cpp')
SYS = $(shell find ./src/sys -name '*.cpp')
APPS = $(shell find ./src/apps -name '*.cpp')

EXEC = bin/$(shell uname)/main

.PHONY: dummy build all objects io sys apps incBC clear run

build: clear incBC objects io sys apps
    @echo "-> Compiling main... "
    @$(CC) -c src/main.cpp $(INC) $(OPTIONS)
    @echo "-> Building environment... "
    @$(CC) $(shell find . -name '*.o') $(LIB) $(OPTIONS) -o $(EXEC) -v
    @echo "-> Removing all objects file from compilation... "
    @rm *.o

objects:
    @echo "-> Building objects files and classes... "
    @$(CC) -c $(OBJS) $(INC) $(OPTIONS)

io:
    @echo "-> Building input/output files and classes..."
    @$(CC) -c $(IO) $(INC) $(OPTIONS)

sys:
    @echo "-> Building system files and classes..."
    @$(CC) -c $(SYS) $(INC) $(OPTIONS)

apps:
    @echo "-> Building all apps files and classes..."
    @$(CC) -c $(APPS) $(INC) $(OPTIONS)

incBC:
    @echo "-> Updated build count..."
    @./incBC.sh

clear:
    clear

run:
    cd bin/$(shell uname)/ amp;amp; clear amp;amp; ./main
 

Теперь, что (по крайней мере, для меня) действительно странно, так это то, что когда я печатаю make , он терпит неудачу один раз из двух… БУКВАЛЬНО один из двух! И когда это не удается, я получаю сообщение об ошибке выше. Что я заметил из этого сообщения, так это то, что в ld команде нет main.o , и, вероятно, поэтому я получаю неопределенную ссылку. Мой вопрос: почему? Почему именно один раз из двух и как я могу это исправить?

Ответ №1:

Это странный makefile. Почему бы просто не написать сценарий оболочки? В этом makefile нет ничего, что использовало бы какие-либо преимущества самого make: он всегда будет перестраивать все каждый раз. Смысл написания makefile вместо сценария оболочки заключается в том, чтобы вы могли избежать перестроения объектов, которые не претерпели изменений.

В любом случае, причина, по которой вы видите сбои, заключается в том, что вы используете $(shell ...) функцию make внутри рецепта. В этом нет необходимости, поскольку рецепт уже запущен в оболочке. Причина, по которой у вас это не получается, заключается в том, что make сначала развернет весь рецепт (все строки), прежде чем запустить ваш рецепт (это должно быть сделано очевидно). Это означает, что, поскольку вы используете $(shell ...) эту find команду, она выполняется перед запуском рецепта, а перед запуском рецепта вы не скомпилировали свой main.o , поэтому find команда не включает его в список найденных объектных файлов. Затем при следующем запуске он main.o существует из предыдущего запуска, поэтому find команда находит его.

Измените эту строку:

 @$(CC) $(shell find . -name '*.o') $(LIB) $(OPTIONS) -o $(EXEC) -v
 

к этому:

 @$(CC) `find . -name '*.o'` $(LIB) $(OPTIONS) -o $(EXEC) -v
 

и это сработает.

Хотя это все еще не очень полезно как makefile.

Комментарии:

1. Спасибо!! Из того, что я прочитал, я полагаю, что мои рецепты (правила, я полагаю) должны иметь вид: ‘***.o:’ чтобы быть более эффективными, а? Тогда, я думаю, это мой следующий шаг! Еще раз спасибо