【问题标题】:Makefile uses same source for every object fileMakefile 对每个目标文件使用相同的源
【发布时间】:2014-05-27 07:05:49
【问题描述】:

我有一个 makefile,它应该将大量源文件编译成单独的目标文件,然后将它们链接到共享库中。

源文件列表存储在变量 SOURCES 中。在编译目标文件的 $(OBJECTS) 目标期间,make 运行命令 $(CC) $(CFLAGS) -c $

这使得命令对每个目标文件使用相同的源文件,给我一堆由 Time.cpp 制作的目标文件,并导致链接器给我一堆已经在每个其他对象中定义的函数错误文件。我怎样才能让这个 makefile 工作?

# Variable setup
# BUILD - Either Debug or Release, specify when running make
# ARCH - Either 32 or 64, specify when running make
# CC - The compiler
# INC - The include directories
# CFLAGS - Compiler flags to use
# LDFLAGS - Linker flags to use
# OBJDIR - Directory for .o files
# BINARY - Output file path
# SOURCES - Path to each individual source file
# OBJECTS - Object files

ifeq ($(and $(ARCH),$(BUILD)),)
    $(error You have either not defined an architecture or build or both, please run "make BUILD=(DEBUG/RELEASE) ARCH=(32/64)")
endif

CC  = g++
INC = -I../../include -I../../extlibs/headers -I../../extlibs/headers/libfreetype/linux
LDFLAGS = -lX11 -lGL -lGLEW -lfreetype -ljpeg -lopenal -lsndfile
CFLAGS  = $(INC) -std=c++0x -fPIC -pthread -m$(ARCH)
OBJDIR  = ./obj/$(BUILD)/$(ARCH)-bit
BINPATH = ./bin/$(BUILD)/$(ARCH)-bit
BINARY  = $(BINPATH)/libTyrant$(ARCH).so
SRCPATH = ../../src/
SOURCES = System/Time.cpp System/Mutex.cpp System/Log.cpp System/Clock.cpp System/Sleep.cpp System/Unix/ClockImpl.cpp System/Unix/MutexImpl.cpp System/Unix/SleepImpl.cpp System/Unix/ThreadImpl.cpp System/Unix/ThreadLocalImpl.cpp System/Lock.cpp System/String.cpp System/ThreadLocal.cpp System/Thread.cpp Audio/SoundRecorder.cpp Audio/SoundBuffer.cpp Audio/SoundSource.cpp Audio/AudioDevice.cpp Audio/ALCheck.cpp Audio/Sound.cpp Audio/Music.cpp Audio/SoundFile.cpp Audio/SoundStream.cpp Audio/SoundBufferRecorder.cpp Audio/Listener.cpp Graphics/RectangleShape.cpp Graphics/VertexArray.cpp Graphics/Shader.cpp Graphics/ConvexShape.cpp Graphics/ImageLoader.cpp Graphics/Sprite.cpp Graphics/RenderTexture.cpp Graphics/BlendMode.cpp Graphics/Shape.cpp Graphics/CircleShape.cpp Graphics/TextureSaver.cpp Graphics/Vertex.cpp Graphics/RenderTextureImpl.cpp Graphics/Texture.cpp Graphics/Text.cpp Graphics/GLExtensions.cpp Graphics/Image.cpp Graphics/RenderTextureImplFBO.cpp Graphics/GLCheck.cpp Graphics/RenderTextureImplDefault.cpp Graphics/Color.cpp Graphics/Transformable.cpp Graphics/RenderTarget.cpp Graphics/Transform.cpp Graphics/View.cpp Graphics/RenderStates.cpp Graphics/RenderWindow.cpp Graphics/Font.cpp Window/JoystickManager.cpp Window/Joystick.cpp Window/Window.cpp Window/Keyboard.cpp Window/GlResource.cpp Window/Unix/JoystickImpl.cpp Window/Unix/WindowImplX11.cpp Window/Unix/GlxContext.cpp Window/Unix/Display.cpp Window/Unix/VideoModeImpl.cpp Window/Unix/InputImpl.cpp Window/VideoMode.cpp Window/Mouse.cpp Window/GlContext.cpp Window/Context.cpp Window/WindowImpl.cpp Network/Ftp.cpp Network/TcpListener.cpp Network/Packet.cpp Network/IpAddress.cpp Network/TcpSocket.cpp Network/Socket.cpp Network/Unix/SocketImpl.cpp Network/UdpSocket.cpp Network/SocketSelector.cpp Network/Http.cpp
OBJECTS = $(addprefix $(OBJDIR)/,$(SOURCES:.cpp=.o))

ifeq ($(BUILD),DEBUG)
    CFLAGS := $(CFLAGS) -g -pg -Og
endif

ifeq ($(BUILD),RELEASE)
    CFLAGS := $(CFLAGS) -s -O3
endif

all: clean $(addprefix $(SRCPATH),$(SOURCES)) $(BINARY)

$(BINARY): $(OBJECTS) $(BINPATH)
    $(CC) $(LDFLAGS) $(OBJECTS) -shared -o $@

$(OBJECTS): $(addprefix $(SRCPATH),$(SOURCES)) $(OBJDIR)
    $(CC) $(CFLAGS) -c $< -o $@

$(OBJDIR):
    mkdir ./obj
    mkdir ./obj/$(BUILD)
    mkdir $@
    mkdir $@/Audio
    mkdir $@/Graphics
    mkdir $@/Network
    mkdir $@/Network/Unix
    mkdir $@/System
    mkdir $@/System/Unix
    mkdir $@/Window
    mkdir $@/Window/Unix

$(BINPATH):
    mkdir ./bin
    mkdir ./bin/$(BUILD)
    mkdir $@

clean:
    rm -rf bin
    rm -rf obj

【问题讨论】:

  • 我觉得根据你的条件改变你的目标是更好的做法——这样每个目标都有一个无条件的方式来构建自己。此外,正如 Beta 所说,make 不太擅长跨目录处理 - 通常的做法是将构建步骤的所有源和目标放在同一个目录中,并有一个单独的 install 步骤来拉结果一起进入最终目的地。因此,这些mkdir 命令不是执行此操作的习惯方式——相反,通常会在不同的子目录中创建针对不同架构的构建。

标签: linux makefile


【解决方案1】:

这里有几个问题。

假设所有源文件都在工作目录中,而目标文件也属于该目录。您可以单独构建每个对象,而不是尝试使用一个命令构建所有对象,并使用模式规则覆盖所有对象:

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

然后您可以制作库的 OBJECTS 先决条件,而 Make 会处理这一切:

$(BINARY): $(OBJECTS)
    $(CC) $(LDFLAGS) $^ -shared -o $@

(一旦你完成了这项工作,你可能会记得 Make 已经有内置规则,例如从 foo.cpp 构建 foo.o,但暂时不要介意。)

但是在您的构建方案中,您将其与其他问题结合在一起:1)您在几个不同的目录中有源文件,2)您想在其他地方构建对象,即 3)在镜像源树的目录树中, 4) 即时构建。

解决所有这些问题将得到一个相当复杂的答案。您已经习惯了其中的哪一个?

【讨论】:

    【解决方案2】:

    我已经让它工作了,虽然它可能不是最佳的。我的解决方案:

    $(BINARY): $(SOURCES) $(BINPATH)
        $(CC) $(LDFLAGS) $(OBJECTS) -shared -o $@
    
    $(SOURCES): $(OBJDIR)
        $(CC) $(CFLAGS) -c $(SRCPATH)$@ -o $(patsubst %.cpp,%.o,$(OBJDIR)/$@)
    

    基本上,我只是将目标从对象文件切换到源文件,将源路径附加到输入文件的目标名称,并将对象目录附加到目标名称,同时还使用 patsubst 更改文件扩展名从 .cpp 到 .o。整个 makefile 被很好地组合在一起,我知道这一点,但它可以工作,这对我的第一个 makefile 来说已经足够了。

    【讨论】:

    • 如果您打算在某一天编写第二个 makefile,那么您现在应该清理这个文件。只是说。
    • 我同意,不幸的是我还没有遇到足够多的 makefile 来真正了解需要修复的内容,或者更确切地说如何修复它。
    猜你喜欢
    • 2021-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多