2010-10-27 43 views
37

Tôi có thư viện C++ được tạo bằng cách sử dụng Makefile. Cho đến gần đây, tất cả các nguồn là trong một thư mục duy nhất, và Makefile đã làm một cái gì đó như thế nàyNguồn từ thư mục con trong Makefile

SOURCES = $(wildcard *.cpp)

mà làm việc tốt.

Bây giờ tôi đã thêm một số nguồn nằm trong thư mục phụ, hãy nói subdir. Tôi biết tôi có thể làm điều này

SOURCES = $(wildcard *.cpp) $(wildcard subdir/*.cpp)

nhưng tôi đang tìm kiếm một cách để tránh quy định cụ thể subdir bằng tay, có nghĩa là, làm wildcard nhìn vào các thư mục con, hoặc tạo ra một danh sách các thư mục con bằng cách nào đó và mở rộng nó với một số wildcard chức năng. Tại thời điểm này, có một giải pháp không đệ quy (có nghĩa là, chỉ mở rộng cấp độ đầu tiên) sẽ là tốt.

Tôi chưa tìm thấy bất kỳ điều gì - phỏng đoán tốt nhất của tôi là sử dụng find -type d để liệt kê các thư mục con, nhưng nó giống như một hack. Có cách nào tích hợp để thực hiện việc này không?

+0

có thể trùng lặp của [Ký tự đại diện đệ quy trong GNU tạo ra?] (Http://stackoverflow.com/questions/2483182/recursive-wildcards-in-gnu-make) –

+0

@Jeroen phải là cách khác vì câu hỏi này có một câu trả lời vượt trội (sử dụng '**'). – rightfold

Trả lời

53

này nên làm điều đó:

SOURCES = $(wildcard *.cpp) $(wildcard */*.cpp) 

Nếu bạn thay đổi bạn quan tâm và muốn có một giải pháp đệ quy (tức là ở bất kỳ độ sâu nào), nó có thể được thực hiện nhưng nó liên quan đến một số hàm Make mạnh hơn. Bạn biết đấy, những cái cho phép bạn làm những điều bạn thực sự không nên.

EDIT:
Jack Kelly chỉ ra rằng $(wildcard **/*.cpp) công trình cho bất kỳ chiều sâu, ít nhất là trên một số nền tảng, sử dụng gnumake 3,81. (Làm cách nào anh ta hiểu được điều đó, tôi không biết.)

+19

Để tìm kiếm ở bất kỳ độ sâu nào, tôi nghĩ '$ (ký tự đại diện **/*. Cpp)' sẽ hoạt động. –

+1

@Jack Kelly: Tôi vừa thử nó và nó không hoạt động (GNU Make 3.81). Nó có hoạt động với phiên bản của bạn không? – Beta

+0

Có. Tôi cũng trên GNU Hãy 3.81, vì vậy có lẽ nó là do cái gì khác (glob?) Hành xử khác nhau trên nền tảng của chúng tôi? Tôi đang ở trên Ubuntu 10,10 amd64. –

9

Common practice là để đặt một Makefile trong mỗi subdir với nguồn khác nhau, sau đó

all: recursive 
    $(MAKE) -C componentX 
    # stuff for current dir 

hoặc

all: recursive 
    cd componentX && $(MAKE) 
    # stuff for current dir 

recursive: true 

Nó có thể là khôn ngoan để đặt cài đặt cho mỗi Makefile trong một Makefile.inc trong thư mục nguồn gốc . Các lực lượng mục tiêu recursivemake để đi vào các thư mục con. Hãy chắc chắn rằng nó không biên dịch lại bất cứ điều gì trong một mục tiêu yêu cầu recursive.

+0

Chắc chắn, nhưng tôi vẫn phải viết "componentX" bằng tay, mà tôi đang cố gắng tránh. – ggambett

+2

Hãy làm theo cách này. Việc biên dịch và liên kết mọi tệp nguồn/đối tượng trong mỗi thư mục con sẽ phá vỡ khi bạn muốn xây dựng một thư viện, xây dựng một tệp với cài đặt trình biên dịch đặc biệt, viết chương trình thử nghiệm, v.v. mọi tệp nguồn duy nhất. Liệt kê một vài thư mục để lặp lại không phải là một nỗi đau. –

+4

Đừng gọi trực tiếp 'make -C'. Bạn cần phải gọi '$ (MAKE) -C' để thay thế. Phiên bản 'make' đang chạy có thể khác với phiên bản' make'. Ngoài ra, không phải là bạn sẽ đặt ra một vòng lặp vô hạn bằng cách chạy '$ (MAKE) $ @'? Cuối cùng, việc đệ quy được coi là có hại bởi một số người. Xem http://miller.emu.id.au/pmiller/books/rmch/ –

7

Đây là một lưu ý phụ và không trả lời cho câu hỏi của bạn nhưng có một bài báo "Recursive Make Considered Harmful". Đó là giá trị đọc.

Đây là liên kết. http://aegis.sourceforge.net/auug97.pdf

+3

+1. Tôi coi thường việc đệ quy và đừng nghĩ rằng ai cũng nên quảng cáo nó nữa. Đưa ra các subdirs make.includes không phải là khó khăn hơn là cho chúng makefiles của riêng chúng. Trong thực tế, nó dễ dàng hơn một chút vì chúng không cần bao gồm một tệp "thần" với tất cả các định nghĩa của dự án. Và hey, bạn không nhận được một loạt các đồ thị phụ thuộc không hoàn chỉnh, crappy! Bài báo đó cũng đưa ra một số lời khuyên tốt khác. –

+2

Trong khi quá trình đệ quy có thể gây hại, kỹ thuật được tìm kiếm trong câu hỏi ban đầu thực sự là cách để * tránh * làm đệ quy, bằng cách làm cho tệp nhận biết cấp cao nhất nhận biết các nguồn trong tất cả các thư mục con. –

13

Nếu bạn không muốn sử dụng makefiles đệ quy, điều này có thể cung cấp cho bạn một số ý tưởng:

subdirs := $(wildcard */) 
sources := $(wildcard $(addsuffix *.cpp,$(subdirs))) 
objects := $(patsubst %.cpp,%.o,$(sources)) 

$(objects) : %.o : %.cpp 
+0

Đó là danh sách các lệnh hữu ích. 'subdirs: = $ (wildcard * /)' là những gì tôi đang tìm kiếm! – Mike

2

Nếu bạn có thể sử dụng lệnh find shell, bạn có thể xác định một chức năng để sử dụng nó.

recurfind = $(shell find $(1) -name '$(2)') 
SRCS := $(call recurfind,subdir1,*.c) $(call recurfind,subdir2,*.cc) $(call recurfind,subdir2,*.cu) \ 
     ... 
16

Ký tự đại diện đệ quy có thể được thực hiện hoàn toàn trong Thực hiện mà không cần gọi trình bao hoặc lệnh tìm.Thực hiện tìm kiếm chỉ bằng cách sử dụng Thực hiện nghĩa là giải pháp này cũng hoạt động trên Windows, không chỉ * nix.

# Make does not offer a recursive wildcard function, so here's one: 
rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)) 

# How to recursively find all files with the same name in a given folder 
ALL_INDEX_HTMLS := $(call rwildcard,foo/,index.html) 

# How to recursively find all files that match a pattern 
ALL_HTMLS := $(call rwildcard,foo/,*.html) 

Dấu gạch chéo theo sau là tên bắt buộc. Hàm rwildcard này không hỗ trợ nhiều ký tự đại diện theo cách mà chức năng ký tự đại diện tích hợp của Make thực hiện, nhưng việc thêm sự hỗ trợ đó sẽ đơn giản với một vài cách sử dụng foreach.

+0

Điều này không hiệu quả đối với tôi. Nó trả về tất cả các thư mục con và tệp bất kể mẫu được cung cấp. – Antimony

+0

@Antimony: (Trong trường hợp bạn đã làm ...) Không thêm các khoảng trống thừa trong $ đệ quy (gọi ...) xung quanh dấu phẩy tách các đối số. Việc thêm các khoảng trắng như vậy sẽ làm thay đổi kết quả. –

Các vấn đề liên quan