2016-02-27 68 views
1

我正在使用GNU makefiles來構建C項目。我想保留一個獨立的構建樹上的所有構建工件以減少混亂。該項目是這樣的:目標文件不匹配隱式規則與模式

$prefix/ 
    include/$tree/program.h 
    source/$tree/program.c 
    build/ 
     objects/$tree/program.o 
     dependencies/$tree/program.d 

其中$prefix表示項目的目錄和$tree表示任意文件夾結構。

我想將source/目錄中的源文件與build/樹中的對象和依賴項文件對應項匹配。所以,我寫了下面的規則:

# Remove the built-in rules 
%.o : %.c 

$(objects_directory)/%.o : $(source_directory)/%.c $(dependencies_directory)/%.d 
    $(compiler_command_line) $(compiler_option_output) [email protected] $< 

$(build_directory)/$(target) : $(objects) 
    $(compiler_command_line) $(compiler_option_output) [email protected] $^ 

製作正確地計算出編譯target,並建立它所需的目標文件。然而,讓停在此點出現錯誤:

No rule to make target 'build/objects/project/program.o' , needed by 'build/program.dll' .

那麼,爲什麼會出現這種情況,如何解決呢?

我通過運行make --print-data-base調查的問題,它的輸出包括:

# Not a target: 
build/objects/project/program.o: 
# Implicit rule search has been done. 
# File does not exist. 
# File has not been updated. 

這表明如預期的前提是不匹配的隱含規則。但是,我覈實,當我試圖通過寫適合我的方式向後,它並匹配:

object := build/objects/project/program.o 
$(object:$(objects_directory)/%.o=$(source_directory)/%.c) 
$(object:$(objects_directory)/%.o=%) 

這些線導致source/project/program.cproject/program,這意味着被正確計算。

我研究過GNU make文檔,我不記得讀過任何暗示這種模式匹配不能在隱式規則定義中發生的事情。


這裏有變量定義:

include_directory := include 
source_directory := source 

build_directory := build 
objects_directory := $(build_directory)/objects 
dependencies_directory := $(build_directory)/dependencies 

sources := $(wildcard $(source_directory)/**/*.c) 
objects := $(sources:$(source_directory)/%.c=$(objects_directory)/%.o) 

# Take the name of the project's directory 
target := $(notdir $(CURDIR)).dll 

compiler_dependency_file = $(patsubst $(source_directory)/%.c,$(dependencies_directory)/%.d,$<) 
compiler_options = -I $(include_directory) -MMD -MF $(compiler_dependency_file) 

CC = gcc 
compiler_command_line = $(CC) $(compiler_options) $(CFLAGS) 
compiler_option_output = -o 

回答

1

事實證明,這不是模式匹配。問題的根源在於隱含規則的依賴先決條件。

依賴文件不應該是首要的先決條件;它應該是與目標文件一起生成的目標之一。

當我再次讀取§本手冊的4.14 Generating Prerequisites Automatically,答案在我跳了出來:

The purpose of the sed command is to translate (for example):

main.o : main.c defs.h 

into:

main.o main.d : main.c defs.h 

雖然我的編譯系統是沒有用的sed,事實main.d是在左側這個例子規則感覺很奇怪。在我的代碼中,它在右側。

當我把我的規則放在左邊時,它就起作用了,問題解決了。錯誤的配方主要是將其副產品之一作爲先決條件。

+0

鏈接器(或編譯器)不使用'.d'。它們是由編譯器生成的makefile,由父Makefile包含, 定義了「foo.o」的依賴關係,該標頭否則不會被稱爲先決條件。當它相對於由'foo.c | cpp'包含的頭部過期時,它們會提示* make *重新編譯*'foo.o'。 –

+0

請參閱 [this](http://stackoverflow.com/questions/8025766/makefile-auto-dependency-generation) [this](http://make.mad-scientist.net/papers/advanced-auto-依賴生成/) 和[這](http://www.microhowto.info/howto/automatically_generate_makefile_dependencies.html) –

+0

@MikeKinghan,我不認爲我理解這個過程,以及我想。根據它們之間的依賴關係,我認爲目標文件和庫都必須以特定順序鏈接。我認爲這是問題['pkg-config'](https://www.freedesktop.org/wiki/Software/pkg-config/)旨在解決的問題。這是不正確的?如果不是,請你澄清一下;我會編輯答案。 –