[c] SRC, OBJ 및 BIN 하위 디렉토리가있는 C 프로젝트 용 Makefile을 어떻게 만들 수 있습니까?

몇 달 전에 저는 Makefile학교 과제를 위해 다음과 같은 일반적인 사항 을 생각해 냈습니다 .

# ------------------------------------------------
# Generic Makefile
#
# Author: yanick.rochon@gmail.com
# Date  : 2010-11-05
#
# Changelog :
#   0.01 - first version
# ------------------------------------------------

# project name (generate executable with this name)
TARGET   = projectname

CC       = gcc -std=c99 -c
# compiling flags here
CFLAGS   = -Wall -I.

LINKER   = gcc -o
# linking flags here
LFLAGS   = -Wall

SOURCES  := $(wildcard *.c)
INCLUDES := $(wildcard *.h)
OBJECTS  := $(SOURCES:.c=*.o)
rm       = rm -f

$(TARGET): obj
    @$(LINKER) $(TARGET) $(LFLAGS) $(OBJECTS)
    @echo "Linking complete!"

obj: $(SOURCES) $(INCLUDES)
    @$(CC) $(CFLAGS) $(SOURCES)
    @echo "Compilation complete!"

clean:
    @$(rm) $(TARGET) $(OBJECTS)
    @echo "Cleanup complete!"

이것은 기본적으로 모든 컴파일 .c하고 .h생성하는 파일을 .o파일 및 실행 파일 projectname과 같은 폴더에있는 모든합니다.

자, 이것을 조금 밀고 싶습니다. 다음 디렉토리 구조로 C 프로젝트를 컴파일하기 위해 Makefile을 어떻게 작성할 수 있습니까?

 ./
 ./Makefile
 ./src/*.c;*.h
 ./obj/*.o
 ./bin/<executable>

즉, C 소스를 ./src/로 컴파일 ./obj/한 다음 모든 것을 링크하여 ./bin/.

다른 Makefile을 읽으려고했지만 위의 프로젝트 구조에서 작동하도록 만들 수는 없습니다. 대신 프로젝트가 모든 종류의 오류로 컴파일되지 않습니다. 물론 완전한 IDE (Monodevelop, Anjuta 등)를 사용할 수 있지만 솔직히 gEdit와 좋은 터미널을 선호합니다.

저에게 작업 솔루션을 제공 할 수있는 전문가가 있습니까? 또는 이것이 어떻게 수행 될 수 있는지에 대한 명확한 정보를 제공합니까? 감사합니다!

** 업데이트 (v4) **

최종 솔루션 :

# ------------------------------------------------
# Generic Makefile
#
# Author: yanick.rochon@gmail.com
# Date  : 2011-08-10
#
# Changelog :
#   2010-11-05 - first version
#   2011-08-10 - added structure : sources, objects, binaries
#                thanks to http://stackoverflow.com/users/128940/beta
#   2017-04-24 - changed order of linker params
# ------------------------------------------------

# project name (generate executable with this name)
TARGET   = projectname

CC       = gcc
# compiling flags here
CFLAGS   = -std=c99 -Wall -I.

LINKER   = gcc
# linking flags here
LFLAGS   = -Wall -I. -lm

# change these to proper directories where each file should be
SRCDIR   = src
OBJDIR   = obj
BINDIR   = bin

SOURCES  := $(wildcard $(SRCDIR)/*.c)
INCLUDES := $(wildcard $(SRCDIR)/*.h)
OBJECTS  := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
rm       = rm -f


$(BINDIR)/$(TARGET): $(OBJECTS)
    @$(LINKER) $(OBJECTS) $(LFLAGS) -o $@
    @echo "Linking complete!"

$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
    @$(CC) $(CFLAGS) -c $< -o $@
    @echo "Compiled "$<" successfully!"

.PHONY: clean
clean:
    @$(rm) $(OBJECTS)
    @echo "Cleanup complete!"

.PHONY: remove
remove: clean
    @$(rm) $(BINDIR)/$(TARGET)
    @echo "Executable removed!"



답변

첫째, 다음 $(OBJECTS)과 같은 이유로 규칙에 문제가 있습니다.

  1. 그것은 일종의 무차별 적 이며 모든 객체의 모든 소스를 전제 조건으로 만듭니다.
  2. 종종 잘못된 소스를 사용 합니다 ( file1.o및에서 발견 한대로 file2.o)
  3. 개체에서 중지하는 대신 실행 파일을 빌드하려고합니다.
  4. 대상의 이름 ( foo.o)은 규칙이 실제로 생성 하는 이름 ( )이 아닙니다 obj/foo.o.

다음을 제안합니다.

OBJECTS  := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)

$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
    $(CC) $(CFLAGS) -c $< -o $@
    @echo "Compiled "$<" successfully!"

$(TARGET)규칙은 대상 이름이 실제로 규칙 빌드 무엇인지 설명하지 않는 것과 같은 문제가있다. 따라서 make여러 번 입력하면 Make는 이유가 없더라도 매번 대상을 다시 작성합니다. 작은 변경으로 다음 사항이 수정되었습니다.

$(BINDIR)/$(TARGET): $(OBJECTS)
    $(LINKER) $@ $(LFLAGS) $(OBJECTS)
    @echo "Linking complete!"

모든 것이 순서대로 이루어지면 더 정교한 종속성 처리를 고려할 수 있습니다. 헤더 파일 중 하나를 수정하면이 메이크 파일은 어떤 개체 / 실행 파일을 다시 빌드해야하는지 알지 못합니다. 그러나 그것은 다른 날을 기다릴 수 있습니다.

편집 :
죄송합니다, $(OBJECTS)위 규칙의 일부를 생략했습니다 . 나는 그것을 고쳤다. (코드 샘플 내에서 “스트라이크”를 사용할 수 있기를 바랍니다.)


답변

-I컴파일러 플래그 (CFLAGS)에 플래그를 추가하여 컴파일러가 소스 파일을 찾아야하는 위치를 표시하고 -o 플래그를 추가하여 바이너리가 남아 있어야하는 위치를 표시 할 수 있습니다.

CFLAGS   = -Wall -I./src
TARGETPATH = ./bin

$(TARGET): obj
    @$(LINKER) $(TARGETPATH)/$(TARGET) $(LFLAGS) $(OBJECTS)
    @echo "Linking complete!"

오브젝트 파일을 obj디렉토리 에 드롭하려면 -o컴파일 할 때 옵션을 사용하십시오 . 또한 $@$< 자동 변수를 살펴보십시오 .

예를 들어,이 간단한 Makefile을 고려하십시오.

CFLAGS= -g -Wall -O3
OBJDIR= ./obj

SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o )
all:$(OBJS)

%.o: %.c
   $(CC) $(CFLAGS) -c $< -o $(OBJDIR)/$@

업데이트>

makefile을 보면 -o플래그를 사용하고 있음을 알 수 있습니다 . 좋은. 계속 사용하되 출력 파일을 작성해야하는 위치를 나타내는 대상 디렉토리 변수를 추가하십시오.


답변

나는 요즘 메이크 파일 작성을 중단했다. 만약 당신의 의도가 계속해서 배우는 것이라면, 그렇지 않으면 Eclipse CDT와 함께 제공되는 좋은 메이크 파일 생성기가있다. 빌드 트리에서 유지 관리 / 다중 프로젝트 지원을 원한다면 다음을 살펴보십시오.

https://github.com/dmoulding/boilermake 이건 꽤 괜찮은 걸 찾았습니다 ..!


답변