Làm thế nào để bạn buộc một makefile để xây dựng lại một mục tiêu


184

Tôi có một makefile xây dựng và sau đó gọi một makefile khác. Vì tệp Makefile này gọi thêm tệp tạo tệp thực hiện công việc nên nó không thực sự thay đổi. Vì vậy, nó cứ nghĩ rằng dự án được xây dựng và cập nhật.

dnetdev11 ~ # make
make: `release' is up to date.

Làm thế nào để tôi buộc makefile xây dựng lại mục tiêu?

clean = $(MAKE) -f ~/xxx/xxx_compile.workspace.mak clean


build = svn up ~/xxx                                                       \
        $(clean)                                                                \
        ~/cbp2mak/cbp2mak -C ~/xxx ~/xxx/xxx_compile.workspace        \
        $(MAKE) -f ~/xxx/xxx_compile.workspace.mak $(1)                    \


release:
        $(build )

debug:
        $(build DEBUG=1)

clean:
        $(clean)

install:
        cp ~/xxx/source/xxx_utility/release/xxx_util /usr/local/bin
        cp ~/xxx/source/xxx_utility/release/xxxcore.so /usr/local/lib

Lưu ý: Xóa tên để bảo vệ người vô tội

Chỉnh sửa: Phiên bản cố định cuối cùng:

clean = $(MAKE) -f xxx_compile.workspace.mak clean;


build = svn up;                                         \
        $(clean)                                        \
        ./cbp2mak/cbp2mak -C . xxx_compile.workspace;   \
        $(MAKE) -f xxx_compile.workspace.mak    $(1);   \


.PHONY: release debug clean install

release:
        $(call build,)

debug:
        $(call build,DEBUG=1)

clean:
        $(clean)

install:
        cp ./source/xxx_utillity/release/xxx_util /usr/bin
        cp ./dlls/Release/xxxcore.so /usr/lib

Vì đây là câu hỏi thường gặp, bạn có muốn chỉnh sửa câu hỏi để hiện đại hơn không? (Có vẻ như .PHONYđó không phải là vấn đề duy nhất của bạn và bạn không thực sự phải chỉnh sửa giải pháp cho câu hỏi, hoặc ít nhất là không còn nữa.)
Keith M

Câu trả lời:


23

Bạn có thể tuyên bố một hoặc nhiều mục tiêu của mình là giả mạo .

Mục tiêu giả mạo là một mục tiêu không thực sự là tên của một tệp; thay vào đó chỉ là một tên cho một công thức được thực thi khi bạn thực hiện một yêu cầu rõ ràng. Có hai lý do để sử dụng mục tiêu giả mạo: để tránh xung đột với một tệp cùng tên và để cải thiện hiệu suất.

...

Mục tiêu giả mạo không nên là điều kiện tiên quyết của tệp mục tiêu thực; nếu có, công thức của nó sẽ được chạy mỗi lần thực hiện để cập nhật tệp đó. Miễn là mục tiêu giả mạo không bao giờ là điều kiện tiên quyết của mục tiêu thực, công thức mục tiêu giả mạo sẽ chỉ được thực hiện khi mục tiêu giả mạo là mục tiêu được chỉ định


68
Câu trả lời này, trong khi nó được "chấp nhận" và "đánh giá cao" thì thực sự không phù hợp. Đầu tiên, nó nói "tuyên bố mục tiêu là giả mạo" nhưng sau đó nó nói "mục tiêu giả mạo không thực sự là tên của một tệp". Chà, nếu mục tiêu của bạn là một tập tin, thì đó là một mâu thuẫn trong câu trả lời. Thứ hai, nó nói "mục tiêu giả mạo không nên là điều kiện tiên quyết của thực tế" - tốt, nếu nó là gì? Câu hỏi ban đầu, không xác định nếu có hoặc không. Câu trả lời đúng là không khai báo mục tiêu của bạn là giả mạo, mà là khai báo một mục tiêu giả mạo bổ sung, và sau đó, phụ thuộc vào các mục tiêu bạn muốn xây dựng lại, vào đó.
Mark Galeck

2
@MarkGaleck. Khi câu trả lời nói rằng "Mục tiêu giả mạo là một mục tiêu không thực sự là tên của một tệp", đó là trích dẫn trực tiếp từ hướng dẫn sử dụng gcc. Nó là hoàn toàn chính xác.
drlolly

"Target" là một thuật ngữ Tạo liên quan đến văn bản ở bên trái dấu hai chấm :, không chỉ là kết quả cuối cùng mà bạn muốn tạo (ví dụ: tệp nhị phân của bạn). Trong câu hỏi, release, debug, clean, và installlà mục tiêu thực hiện, không xxx_utilhay xxxcore.sohoặc bất cứ điều gì khác.
Keith M

728

Việc -Bchuyển đổi để thực hiện, có hình thức dài là --always-make, nói makeđể bỏ qua dấu thời gian và thực hiện các mục tiêu được chỉ định. Điều này có thể đánh bại mục đích sử dụng make, nhưng nó có thể là những gì bạn cần.


4
@MarkKCowan Tôi hoàn toàn đồng ý! Tùy chọn này chính xác là những gì tôi đang tìm kiếm, không phải là một số cách khắc phục như Dave đề xuất.
Maarten Bamelis

8
Nhắc nhở với phương pháp này là, nó chỉ xây dựng nhiều thứ. Cụ thể với autotools, tôi đã thấy nó chạy lại cấu hình .. Tôi muốn một giải pháp dựa trên LD_PRELOAD có thể được xây dựng !!
vrdhn

có, và nó thậm chí có thể viết lại các tập tin bạn không muốn! chẳng hạn như các thư viện hệ thống toàn cầu xuất hiện trong phần phụ thuộc và được xây dựng lại và ghi đè lên ...
Julio Guerra

18

Một mẹo được sử dụng để ghi lại trong sổ tay của Sun makelà sử dụng mục tiêu (không tồn tại) '.OROR'. Bạn có thể làm điều này bằng cách tạo một tệp, force.mk, có chứa:

.FORCE:
$(FORCE_DEPS): .FORCE

Sau đó, giả sử tệp tạo tệp hiện tại của bạn được gọi makefile, bạn có thể chạy:

make FORCE_DEPS=release -f force.mk -f makefile release

.FORCEkhông tồn tại, bất cứ điều gì phụ thuộc vào nó sẽ bị lỗi thời và được xây dựng lại.

Tất cả điều này sẽ làm việc với bất kỳ phiên bản nào của make; trên Linux, bạn có GNU Make và do đó có thể sử dụng mục tiêu .PHONY như đã thảo luận.

Nó cũng đáng để xem xét tại sao makecoi việc phát hành được cập nhật. Điều này có thể là do bạn có một touch releaselệnh trong số các lệnh được thực thi; có thể là do có một tệp hoặc thư mục gọi là 'phát hành' tồn tại và không có phụ thuộc và do đó được cập nhật. Vậy thì có lý do thực sự ...


14

Một số người khác đề nghị .PHONY chắc chắn là chính xác. .PHONY nên được sử dụng cho bất kỳ quy tắc nào so sánh ngày giữa đầu vào và đầu ra không hợp lệ. Vì bạn không có bất kỳ mục tiêu nào của biểu mẫu, output: inputbạn nên sử dụng .PHONY cho TẤT CẢ chúng!

Tất cả những gì đã nói, có lẽ bạn nên xác định một số biến ở đầu tệp tạo tệp của mình cho các tên tệp khác nhau và xác định quy tắc tạo thực có cả phần đầu vào và đầu ra để bạn có thể sử dụng các lợi ích của việc tạo, cụ thể là bạn sẽ chỉ thực sự biên dịch những thứ cần thiết để copmile!

Chỉnh sửa: thêm ví dụ. Chưa được kiểm tra, nhưng đây là cách bạn làm .PHONY

.PHONY: clean    
clean:
    $(clean)

1
Chà nếu bạn có thể chỉ cho tôi một ví dụ thì nó sẽ rất tuyệt. Atm tôi chỉ hack nó để cố gắng làm cho cái đập hoạt động: P
Lodle

1
Vị trí của .PHONYmục tiêu không quan trọng. Nó có thể là bất cứ nơi nào trong Makefile.
Adrian W

5

Nếu tôi nhớ lại chính xác, 'make' sử dụng dấu thời gian (thời gian sửa đổi tệp) để xác định liệu mục tiêu có được cập nhật hay không. Một cách phổ biến để buộc xây dựng lại là cập nhật dấu thời gian đó, sử dụng lệnh 'chạm'. Bạn có thể thử gọi 'touch' trong tệp tạo tệp của mình để cập nhật dấu thời gian của một trong các mục tiêu (có thể là một trong những tệp phụ đó), có thể buộc Make thực hiện lệnh đó.


5

Kỹ thuật đơn giản này sẽ cho phép makefile hoạt động bình thường khi không muốn buộc. Tạo một mục tiêu mới gọi là lực ở cuối tệp thực hiện của bạn . Các lực lượng mục tiêu sẽ chạm vào một tập tin mà mục tiêu mặc định của bạn phụ thuộc vào. Trong ví dụ dưới đây, tôi đã thêm touch myprogram.cpp . Tôi cũng đã thêm một cuộc gọi đệ quy để thực hiện . Điều này sẽ khiến mục tiêu mặc định được thực hiện mỗi khi bạn gõ lực .

yourProgram: yourProgram.cpp
       g++ -o yourProgram yourProgram.cpp 

force:
       touch yourProgram.cpp
       make

Bạn không bao giờ nên sử dụng makebên trong Makefile. Sử dụng $(MAKE)thay thế.
Benjamin Crawford Ctrl-Alt-Tut

3

Tôi đã thử nó và nó làm việc cho tôi

thêm các dòng này vào Makefile

clean:
    rm *.o output

new: clean
    $(MAKE)     #use variable $(MAKE) instead of make to get recursive make calls

lưu và gọi ngay

make new 

và nó sẽ biên dịch lại mọi thứ một lần nữa

Chuyện gì đã xảy ra?

1) 'mới' gọi sạch. 'Clean' do 'rm', loại bỏ tất cả các tệp đối tượng có phần mở rộng là '.o'.

2) 'mới' gọi 'thực hiện'. 'Make' thấy rằng không có tệp '.o', vì vậy nó sẽ tạo lại tất cả '.o'. sau đó trình liên kết liên kết tất cả các tệp .o int một đầu ra thực thi

Chúc may mắn


1
Trong công thức để newsử dụng tốt $(MAKE)hơnmake
Basile Starynkevitch

1

Theo đệ quy làm cho mọi người coi là có hại, bạn nên tránh gọi $(MAKE)! Trong trường hợp bạn hiển thị, điều đó vô hại, bởi vì đây thực sự không phải là một tệp tạo ra, chỉ là một tập lệnh bao bọc, có thể cũng đã được viết trong Shell. Nhưng bạn nói rằng bạn tiếp tục như vậy ở cấp độ đệ quy sâu hơn, vì vậy bạn có thể đã gặp phải các vấn đề được thể hiện trong bài tiểu luận mở mắt đó.

Tất nhiên với GNU làm cho nó cồng kềnh để tránh. Và mặc dù họ nhận thức được vấn đề này, đó là cách làm việc được ghi chép lại của họ.

OTOH, makepp đã được tạo ra như một giải pháp cho vấn đề này. Bạn có thể viết các tệp tạo tệp của bạn theo cấp độ thư mục, nhưng tất cả chúng được vẽ lại với nhau thành một cái nhìn đầy đủ về dự án của bạn.

Nhưng makefiles kế thừa được viết đệ quy. Vì vậy, có một cách giải quyết mà $(MAKE)không làm gì khác ngoài việc đưa các cuộc điều tra trở lại quy trình trang điểm chính. Chỉ khi bạn làm những thứ dư thừa hoặc tệ hơn, mâu thuẫn giữa các lần gửi của bạn, bạn phải yêu cầu --traditional-recursive-make(tất nhiên là phá vỡ lợi thế này của makepp). Tôi không biết các tệp tạo tệp khác của bạn, nhưng nếu chúng được viết sạch sẽ, với các bản dựng lại cần thiết sẽ tự động xảy ra, mà không cần bất kỳ bản hack nào được đề xuất ở đây bởi những người khác.


Không trả lời câu hỏi: tiếp xúc với ý chính và nên là một nhận xét không phải là một câu trả lời.
flungo

Có lẽ tôi đã không đủ rõ ràng. Với makepp , toàn bộ trình bao bọc này không cần thiết. Bằng cách biết chính xác các phụ thuộc (tất cả chúng, không chỉ những gì được liệt kê sau :), nó sẽ luôn được xây dựng lại khi cần thiết.
Daniel

1

Nếu bạn không cần giữ bất kỳ kết quả đầu ra nào bạn đã biên dịch thành công

nmake /A 

xây dựng lại tất cả


0

Nó thực sự phụ thuộc vào mục tiêu là gì. Nếu đó là một mục tiêu giả mạo (tức là mục tiêu KHÔNG liên quan đến một tệp), bạn nên khai báo nó là .PHONY.

Tuy nhiên, nếu mục tiêu không phải là mục tiêu giả mạo nhưng bạn chỉ muốn xây dựng lại nó vì một số lý do (một ví dụ là khi bạn sử dụng macro tiền xử lý __TIME__), bạn nên sử dụng lược đồ FORCE được mô tả trong câu trả lời tại đây.



0

Nó đã được đề cập, nhưng nghĩ rằng tôi có thể thêm vào bằng cách sử dụng touch

Nếu bạn touchtất cả các tệp nguồn sẽ được biên dịch, touchlệnh sẽ thay đổi dấu thời gian của tệp thành thời gian hệ thống mà touchlệnh được thực thi.

Bảng thời gian của tệp nguồn là những gì makesử dụng để "biết" một tệp đã thay đổi và cần được biên dịch lại

Ví dụ: Nếu dự án là một dự án c ++, thì hãy làm touch *.cpp, sau đó chạy makelại và thực hiện nên biên dịch lại toàn bộ dự án.


0

Như abernier đã chỉ ra, có một giải pháp được đề xuất trong hướng dẫn sử dụng GNU, sử dụng mục tiêu 'giả' để buộc xây dựng lại mục tiêu:

clean: FORCE
        rm $(objects)
FORCE: ; 

Điều này sẽ chạy sạch, bất kể phụ thuộc nào khác.

Tôi đã thêm dấu chấm phẩy vào giải pháp từ hướng dẫn, nếu không thì cần một dòng trống.


-1

Trên hệ thống Linux của tôi (Centos 6.2), có một sự khác biệt đáng kể giữa việc khai báo mục tiêu .PHONY và tạo một phụ thuộc giả mạo trên FORCE, khi quy tắc thực sự tạo ra một tệp khớp với mục tiêu. Khi tệp phải được tạo lại mỗi lần, nó yêu cầu cả phụ thuộc giả FORCE trên tệp và .PHONY cho phụ thuộc giả.

Sai lầm:

date > $@

đúng:

FORCE
    date > $@
FORCE:
    .PHONY: FORCE

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.