Tiếng AnhTiếng PhápTiếng Tây Ban Nha

Ad


Biểu tượng yêu thích OnWorks

makepp_cookbook - Trực tuyến trên đám mây

Chạy makepp_cookbook trong nhà cung cấp dịch vụ lưu trữ miễn phí OnWorks trên Ubuntu Online, Fedora Online, trình giả lập trực tuyến Windows hoặc trình mô phỏng trực tuyến MAC OS

Đây là lệnh makepp_cookbook có thể chạy trong nhà cung cấp dịch vụ lưu trữ miễn phí OnWorks bằng cách sử dụng một trong nhiều máy trạm trực tuyến miễn phí của chúng tôi như Ubuntu Online, Fedora Online, trình giả lập trực tuyến Windows hoặc trình mô phỏng trực tuyến MAC OS

CHƯƠNG TRÌNH:

TÊN


makepp_cookbook - Cách tốt nhất để thiết lập trang điểm cho các tình huống khác nhau

MÔ TẢ


Tôi phát hiện ra rằng thực tế không ai đọc sách hướng dẫn cho một công cụ chế tạo, bởi vì thành thật mà nói
không ai thực sự quan tâm đến chính quá trình làm - chúng tôi chỉ quan tâm đến kết quả.
Vì vậy, cuốn sách nấu ăn này đã được tổng hợp lại với hy vọng rằng mọi người sẽ có thể có được những gì họ cần
nhanh chóng từ các ví dụ mà không cần phải tìm hiểu kỹ hướng dẫn. Điều này cho thấy cách nhập
câu hỏi, trong khi hướng dẫn cài đặt và các bước gặp phải sẽ được tìm thấy trong
Các câu hỏi thường gặp.

Xây dựng thư viện
Do bạn có thật không nhu cầu a thư viện?

Tôi đã thấy một số chương trình lớn bao gồm một số lượng lớn các mô-đun, mỗi
nằm trong thư mục riêng của nó. Thông thường, mỗi thư mục được đưa vào thư viện riêng của nó,
và sau đó chương trình cuối cùng liên kết với tất cả các thư viện.

Trong nhiều trường hợp, tôi nghĩ thay vì sử dụng thư viện, có một cách tiếp cận tốt hơn. Thư viện
không thực sự là giải pháp phù hợp nếu mỗi mô-đun không thể hoặc sẽ không được sử dụng lại trong bất kỳ mô-đun nào khác
chương trình, bởi vì sau đó bạn nhận được tất cả các nhược điểm của các thư viện và không có
thuận lợi. Thư viện hữu ích trong các trường hợp sau:

1. Khi bạn có một loạt các chương trình con phải được liên kết với một số
chương trình và không có chương trình nào thực sự sử dụng 100% chương trình con - mỗi chương trình sử dụng
tập hợp con khác nhau. Trong trường hợp này, có lẽ nên sử dụng thư viện tĩnh (a
.a hoặc một tệp lưu trữ).

2. Khi bạn có một mô-đun cần được liên kết với một số chương trình khác nhau, và bạn
muốn tải động để mỗi chương trình không cần phải có một bản sao riêng biệt của
thư viện. Thư viện động có thể tiết kiệm không gian tệp thực thi và đôi khi nâng cao
hiệu suất hệ thống vì chỉ có một bản sao của thư viện được tải cho tất cả
các chương trình khác nhau sử dụng nó.

3. Khi thời gian liên kết của bạn quá dài, hãy sử dụng thư viện được chia sẻ cho các phần lớn
chương trình có thể tăng tốc liên kết một cách đáng kể.

Sử dụng thư viện tĩnh có một nhược điểm chính: trên một số hệ thống (ví dụ: Linux), thứ tự
trong đó bạn liên kết các thư viện là cực kỳ quan trọng. Trình liên kết xử lý thư viện
theo thứ tự được chỉ định trên dòng lệnh của nó. Nó lấy mọi thứ nó nghĩ nó cần từ
mỗi thư viện, sau đó chuyển sang thư viện tiếp theo. Nếu một số thư viện tiếp theo đề cập đến một
biểu tượng chưa được kết hợp từ thư viện trước đó, trình liên kết không
biết quay lại và lấy nó từ thư viện trước đó. Do đó, nó có thể cần thiết
để liệt kê thư viện nhiều lần trên dòng lệnh của trình liên kết. (Tôi đã làm việc trong một dự án
nơi chúng tôi phải lặp lại toàn bộ danh sách các thư viện ba lần. Dự án này là những gì đã làm
tôi thích cách tiếp cận thay thế được đề xuất bên dưới, đó là liên kết gia tăng.)

Sử dụng thư viện động có một số nhược điểm. Đầu tiên, chương trình của bạn có thể hơi
khởi động chậm hơn nếu thư viện chưa được một số chương trình khác sử dụng, bởi vì
nó phải được tìm thấy và tải. Thứ hai, có thể là một rắc rối thực sự để có được tất cả các động lực
thư viện được cài đặt ở các vị trí chính xác; bạn không thể chỉ sao chép chương trình thực thi,
bạn cũng phải đảm bảo rằng bạn sao chép tất cả các thư viện của nó. Thứ ba, trên một số hệ thống, nó
khó gỡ lỗi mã bên trong các thư viện được chia sẻ vì trình gỡ lỗi không hỗ trợ
họ tốt.

Nếu mô-đun của bạn sẽ không bao giờ được sử dụng trong bất kỳ chương trình nào khác, thì có rất ít lý do để sử dụng
thư viện: bạn nhận được tất cả những bất lợi của việc sử dụng thư viện và không có ưu điểm nào.
Kỹ thuật tôi thích là sử dụng liên kết gia tăng, nếu nó có sẵn.

Đây là cách bạn có thể thực hiện việc này trên Linux:

my_module.o: $ (filter_out my_module.o, $ (ký tự đại diện * .o))
ld -r -o $ (đầu ra) $ (đầu vào)

Điều này sẽ làm là tạo ra một .o tệp được gọi là my_module.o, sẽ bao gồm
tất cả .o các tệp trong thư mục con này. Trình liên kết sẽ giải quyết càng nhiều
tham chiếu như nó có thể, và sẽ để lại các tham chiếu còn lại sẽ được giải quyết trong
giai đoạn tiếp theo của liên kết. Ở cấp cao nhất, khi cuối cùng bạn xây dựng chương trình của mình,
thay vì liên kết với libmy_module.a or libmy_module.so, bạn chỉ cần liên kết với
my_module.o. Khi bạn liên kết .o các tệp, bạn không gặp vấn đề với sự phụ thuộc vào thứ tự trong
dòng lệnh linker.

Để trang điểm con số ra cái nào thư viện mô-đun đang cần thiết

Ngay cả khi bạn có một thư viện thực sự, trong đó một chương trình nhất định chỉ cần một vài tệp từ nó
(thay vì mọi mô-đun đơn lẻ), makepp có thể tìm ra mô-đun nào là
cần thiết từ thư viện và chỉ bao gồm những thứ trong bản dựng. Điều này có thể tiết kiệm biên dịch
thời gian nếu bạn đang phát triển thư viện cùng với một chương trình, bởi vì bạn không bận tâm
biên dịch các mô-đun thư viện không cần thiết cho chương trình cụ thể mà bạn đang làm việc.

Nếu thư viện của bạn tuân thủ nghiêm ngặt quy ước rằng tất cả các hàm hoặc lớp được khai báo trong
một tập tin xyz.h được triển khai hoàn toàn trong một tệp nguồn biên dịch thành xyz.o (tức là bạn
không chia nhỏ việc triển khai thành xyz1.oxyz2.o), sau đó bạn có thể sử dụng
Hàm "$ (inv_objects)" để yêu cầu makepp chỉ lấy ra các mô-đun có liên quan từ
thư viện. Điều này có thể hoạt động tốt một cách đáng ngạc nhiên đối với các thư viện có thậm chí hàng chục tệp bao gồm.
Về cơ bản, "$ (inv_objects)" kiểm tra danh sách .h các tệp được bao gồm và giao diện
cho tương ứng .o các tập tin. Nếu bạn đang phát triển nhanh chóng một thư viện và một chương trình
cùng với nhau, điều này có thể tiết kiệm thời gian biên dịch, bởi vì bạn không bao giờ bận tâm đến việc biên dịch các mô-đun của
thư viện mà chương trình không sử dụng.

Đây là một ví dụ về cách tôi sử dụng nó:

my_program: $ (suy ra_các dự án * .o, $ (LIB1) / *. o $ (LIB2) / *. o)
$ (CXX) $ (đầu vào) -o $ (đầu ra) $ (SYSTEM_LIBRARIES)

Hàm "$ (inv_objects)" trả về đối số đầu tiên của nó (sau khi thực hiện ký tự đại diện
mở rộng trên đó), và cũng xem qua danh sách các tệp trong đối số thứ hai của nó, cho
tệp có tên giống với tên của bất kỳ .h các tệp được bao gồm bởi bất kỳ tệp nào trong tệp đầu tiên của nó
tranh luận. Nếu tìm thấy bất kỳ tệp nào như vậy, chúng sẽ được thêm vào danh sách.

Xây dựng a tĩnh thư viện

Nếu bạn chắc chắn rằng bạn thực sự cần một thư viện và liên kết gia tăng không khả dụng hoặc
không phải là những gì bạn muốn làm, có một số cách để làm điều đó. Đầu tiên, đây là một ví dụ
nơi tất cả các tệp được liệt kê rõ ràng:

LIBRARY_FILES = abcde

libmine.a: $ (LIBRARY_FILES) .o
& rm -f $ (đầu ra)
$ (AR) cr $ (đầu ra) $ (đầu vào)
ranlib $ (output) # Có thể không cần thiết, tùy thuộc vào hệ điều hành của bạn.

& Rm là lệnh "rm" nội trang của makepp. Nếu bạn đã quen với việc viết trang điểm, bạn có thể
một chút ngạc nhiên bởi lệnh này; bạn có thể quen với một cái gì đó giống như thế này hơn:

libmine.a: $ (LIBRARY_FILES) .o
$ (AR) ru $ @ $? # Không được khuyến khích!!!!!!!
ranlib $ (đầu ra)

$ ở đâu? (còn được gọi là "$ (change_inputs)") là một biến tự động có nghĩa là bất kỳ tệp nào
đã thay đổi kể từ lần cuối cùng thư viện được xây dựng và $ @ cũng gần giống
là "$ (đầu ra)".

Cách tiếp cận này không được khuyến khích vì một số lý do:

· Giả sử bạn xóa một tệp nguồn khỏi thư mục hiện tại. Nó vẫn ở trong
thư viện, vì bạn đã không xây dựng lại thư viện từ đầu. Kết quả là, bất cứ điều gì
rằng các liên kết với thư viện này sẽ cũ .o và điều đó có thể làm hỏng
xây dựng. (Tôi đã từng vô cùng bối rối vì điều này khi tôi cố gắng xóa mã chết
từ một dự án: Tôi tiếp tục xóa các tệp và nó vẫn được liên kết, vì vậy tôi nghĩ rằng mã là
đã chết. Tuy nhiên, khi ai đó xây dựng lại dự án từ đầu, nó không liên kết bất kỳ
hơn! Vấn đề là cái cũ .o các tệp vẫn còn trong kho lưu trữ.)

Ngoài ra, tùy thuộc vào các tùy chọn của bạn đối với "ar" và việc triển khai "ar" của bạn (ví dụ: nếu bạn
sử dụng tùy chọn "q" thay vì "r"), bạn có thể kết thúc với một số phiên bản của
tương tự .o Bên trong .a tập tin. Nếu các phiên bản khác nhau xác định các hình cầu khác nhau,
trình liên kết có thể cố gắng thu hút cả hai. Đây có lẽ là một điều tồi tệ.

Đây là lý do tại sao trước tiên chúng tôi xóa tệp thư viện và tạo nó từ đầu. Điều này sẽ
mất nhiều thời gian hơn một chút so với việc chỉ cập nhật các mô-đun trong thư viện, nhưng không lâu hơn; trên
một máy tính hiện đại, lượng thời gian sử dụng ar chương trình rất nhỏ so với
đối với những gì trình biên dịch C đảm nhận trong một bản dựng thông thường, vì vậy nó không đáng lo ngại
về.

· Một trong những cách makepp cố gắng đảm bảo các bản dựng chính xác là nó sẽ
tự động xây dựng lại nếu dòng lệnh xây dựng một mục tiêu nhất định đã thay đổi. Nhưng
sử dụng $? biến có thể gây ra sự cố, vì mỗi lần cập nhật thư viện,
lệnh xây dựng là khác nhau. (Bạn có thể ngăn chặn điều này bằng cách sử dụng
": build_check ignore_action"; xem makepp_build_check để biết thêm chi tiết.)

· Cập nhật kho lưu trữ thay vì xây dựng lại nó sẽ khiến makepp không thể
đặt tệp đúng cách vào bộ đệm ẩn bản dựng (xem makepp_build_cache để biết thêm chi tiết).

Đôi khi, bạn có thể thấy rằng việc liệt kê tất cả các tệp là một chút khó khăn, đặc biệt là nếu
dự án đang được phát triển nhanh chóng và danh sách các tệp liên tục thay đổi. Nó
có thể dễ dàng hơn để xây dựng thư viện bằng cách sử dụng các ký tự đại diện, như sau:

libmine.a: $ (only_targets * .o)
& rm $ (đầu ra)
$ (AR) cr $ (đầu ra) $ (đầu vào)

Điều này đặt tất cả .o các tệp trong thư mục hiện tại vào thư viện. Ký tự đại diện
phù hợp với bất kỳ .o tệp tồn tại hoặc có thể được tạo, vì vậy nó sẽ hoạt động ngay cả khi tệp không
tồn tại.

Hàm "only_targets" được sử dụng để loại trừ .o các tệp không có tương ứng
bất kỳ tệp nguồn nào nữa. Giả sử bạn có một tệp được gọi là xyz.c mà bạn đã từng đưa vào
thư viện. Điều này có nghĩa là có một xyz.o tập tin nằm xung quanh. Bây giờ bạn xóa xyz.c
bởi vì nó đã lỗi thời, nhưng bạn quên xóa xyz.o. Không có "only_targets"
chức năng, xyz.o vẫn sẽ được đưa vào danh sách .o các tệp có trong thư viện.

Xây dựng a năng động thư viện

Quá trình xây dựng thư viện động hoàn toàn phụ thuộc vào hệ thống. Tôi rất muốn
khuyên bạn nên sử dụng libtool để xây dựng một thư viện động (xem
<http://www.gnu.org/software/libtool/>), vì vậy bạn không cần phải tìm cách làm điều đó trên
nền tảng của bạn và để makefile của bạn sẽ tiếp tục hoạt động ngay cả khi bạn chuyển sang
hệ điều hành khác nhau. Xem tài liệu libtool để biết chi tiết. Đây là một Makefile mẫu:

LIBTOOL: = libtool

libflick.la: $ (only_targets * .lo)
$ (LIBTOOL) --mode = link $ (CC) $ (đầu vào) -o $ (đầu ra)

% .lo:% .c
$ (LIBTOOL) --mode = biên dịch $ (CC) $ (CFLAGS) $ (BAO GỒM) -c $ (đầu vào) -o $ (đầu ra)

Xây dựng on một số khác nhau máy or mạng
Một trong những vấn đề khó chịu nhất với trang điểm là chúng hầu như không bao giờ hoạt động khi bạn
chuyển sang một máy khác hoặc một mạng khác. Nếu trang điểm của bạn phải hoạt động
mọi máy móc có thể có trên hành tinh, thì bạn có thể cần một số loại cấu hình
kịch bản. Nhưng nếu bạn chỉ phải làm việc trên một số máy khác nhau, có một số cách
bạn có thể tiếp cận vấn đề này:

Sử dụng a khác nhau bao gồm hồ sơ in tất cả các các môi trường

Ở đầu mỗi makefile, bạn có thể bao gồm một dòng như sau:

bao gồm system_defs.mk

Tập tin system_defs.mk thường sẽ được đặt ở một nơi khác nhau cho mỗi
môi trường. Nếu bạn muốn các thư mục xây dựng của mình giống hệt nhau trên tất cả các máy, hãy đặt
system_defs.mk trong một thư mục phía trên các thư mục xây dựng hoặc cung cấp một đường dẫn bao gồm
để makepp bằng cách sử dụng tùy chọn dòng lệnh "-I".

Điều này thường hơi khó làm, nhưng nó hoạt động tốt nếu có một số lượng lớn
sự khác biệt

Sử dụng if báo cáo

Đây là cách xấu nhất để làm điều đó, nhưng nó thường sẽ hiệu quả.

ifsys i386
CC: = gcc
khác ifsys sun4u
CC: = cc
ifsys hpux11 khác
CC = c89
endif

Nếu tất cả những gì bạn cần làm là tìm một vài chương trình hoặc thư viện hoặc bao gồm các tệp trong các
những nơi, có thể có nhiều cách tốt hơn (xem bên dưới).

tìm_chương trình, đầu tiên_có sẵn, tìm tập tin

Các chức năng này có thể tìm kiếm nhiều thư mục khác nhau trong hệ thống của bạn để tìm
các tệp thích hợp. Tất nhiên, điều này không mạnh bằng tập lệnh cấu hình, nhưng tôi thấy nó
có ích. Ví dụ, tôi làm như sau:

CXX; = $ (chương trình tìm kiếm g ++ c ++ pg ++ cxx CC aCC)
# Chọn trình biên dịch C ++ đầu tiên có sẵn trong PATH.
# (Ngẫu nhiên, nếu bạn không xác định CXX, điều này
# là cách nó được định nghĩa.)
TCL_INCLUDE; = -I $ (dir_noslash $ (findfile tcl.h, \
/usr/local/stow/tcl-8.4.5-nothread/include \
/usr/include/tcl8.4 / usr / include / tcl \
/net/na1/tcl8.4a3/include /net/na1/tcl8.4a3/include))
# $ (findfile) tìm kiếm tcl.h trong mỗi mục được chỉ định
# thư mục và trả về đường dẫn đầy đủ. Đây là sau đó
# được chuyển đổi thành một tùy chọn biên dịch bằng cách loại bỏ
# tên tệp (rời khỏi thư mục) và bắt đầu bằng -I.
% .o:% .cpp
$ (CXX) $ (CXXFLAGS) $ (TCL_INCLUDE) $ (đầu vào) -o $ (đầu ra)

TCL_LIB; = $ ((first_available
/usr/local/stow/tcl-8.4.5-nothread/lib/libtcl8.4.so
/usr/lib/libtcl8.4.so /usr/lib/libtcl.so
/net/na1/tcl8.4a3/lib/libtcl8.4.a
/net/na1/tcl8.4a3/lib/libtcl8.4.sl))
# Tìm thư viện Tcl ở đâu. Điều này sau đó rõ ràng
# được liệt kê trên lệnh liên kết:
my_program: * .o
$ (CXX) $ (CXXFLAGS) $ (đầu vào) -o $ (đầu ra) $ (TCL_LIB)

Hãy lợi thế of Perl's cấu hình thông tin

Các kỹ thuật trên có thể không đủ nếu bạn cần thêm một số thông tin về
hệ thống của bạn, chẳng hạn như có tồn tại một đoạn kép dài hay không, hoặc thứ tự byte là gì. Tuy vậy,
perl đã tính toán những điều này, vì vậy bạn có thể chỉ cần sử dụng các câu trả lời của nó.

Tập lệnh tự động định cấu hình của Perl cung cấp tất cả thông tin cấu hình của nó thông qua
băm% Config. Không có cú pháp nào để truy cập hàm băm Perl trực tiếp trong makepp, nhưng bạn có thể
thả vào Perl và đặt các biến vô hướng, có thể truy cập trực tiếp từ makepp:

perl_bắt đầu
# Tìm nạp các giá trị từ băm cấu hình.
sử dụng Config;
$ CC = $ Cấu hình {'cc'}; # C trình biên dịch perl đã sử dụng;
$ byteorder_flags = "-DBYTEORDER = $ Cấu hình {'byteorder'}";
$ longdouble_defined = $ Cấu hình {'d_longdbl'} eq 'xác định';
$ CFLAGS_for_shared_libs = $ Cấu hình {'cccdlflags'};
$ LDFLAGS_for_shared_libs = $ Cấu hình {'ccdlflags'};
perl_end

Ngoài ra, khi bạn đã thực hiện xong 'use Config', bạn có thể sử dụng câu lệnh "$ (perl)", như
điều này:

SHARED_LIB_EXTENSION: = $ (perl $ Cấu hình {'dlext'})

Nhập "perldoc Config" để xem thông tin nào có sẵn thông qua băm% Config.

Cấu hình của Perl là một nơi tốt để lấy những thứ như thông tin về kiểu số nguyên, byte
đơn đặt hàng và những thứ khác thường yêu cầu một tập lệnh cấu hình riêng để xác định vị trí. Một số
thông tin của nó liên quan đến sự hiện diện của những thứ trong hệ thống tệp có thể không
có giá trị. Ví dụ: $ Config {'cc'} đề cập đến trình biên dịch C mà perl được xây dựng với,
có thể không giống với trình biên dịch C mà bạn muốn sử dụng. Trên thực tế, nó thậm chí có thể không tồn tại
trên hệ thống của bạn, vì bạn có thể đã cài đặt Perl thông qua một gói nhị phân.

Lời khuyên cho sử dụng ký tự đại diện
Phù hợp tất cả các các tập tin ngoại trừ a nhất định tập hợp con

Các ký tự đại diện của Makepp hiện không có bất kỳ cách nào để khớp với tất cả các tệp ngoại trừ một số
nhưng bạn có thể làm điều đó với sự kết hợp của nhiều chức năng.

Ví dụ: giả sử bạn có chương trình thử nghiệm cho từng mô-đun trong thư viện, nhưng bạn không
muốn đưa các chương trình thử nghiệm vào thư viện. Nếu tất cả các chương trình thử nghiệm bắt đầu bằng
thử nghiệm, thì bạn có thể loại trừ chúng như thế này:

libproduction.a: $ (kiểm tra filter_out *, $ (ký tự đại diện * .o))

Các hàm "$ (filter)" và "$ (filter_out)" là một tập hợp các bộ lọc rất hiệu quả để thực hiện
tất cả các loại hoạt động giao nhau và chênh lệch tập hợp. Ví dụ,

SUBDIRS; = $ (filter_out * test * * $ (ARCH) *, $ (tìm shell. -Type d -print))
# Trả về tất cả các thư mục con không có
# "test" hoặc $ (ARCH) trong chúng.

$ (bộ lọc $ (patsubst test_dir / test _%. o,% .o, $ (ký tự đại diện test_dir / *. o)), \
$ (ký tự đại diện * .o))
# Trả về danh sách các tệp .o hiện tại
# thư mục mà có một
# test _ *. o tệp trong thư mục con test_dir.
$ (filter_out $ (patsubst man / man3 /%. 3,% .o, $ (wildcard man / man3 / *. 3)), \
$ (ký tự đại diện * .o))
# Trả về danh sách các tệp .o hiện tại
# thư mục không có trang hướng dẫn sử dụng
# có cùng tên tệp trong thư mục con man / man3.

Sử dụng các "$ (only_targets )" chức năng đến loại bỏ .o các tập tin

Giả sử bạn đang xây dựng một chương trình hoặc một thư viện bằng lệnh xây dựng như sau:

chương trình: * .o
$ (CC) $ (đầu vào) -o $ (đầu ra)

Giả sử bây giờ bạn xóa một tệp nguồn. Nếu bạn quên xóa tương ứng .o tập tin,
nó vẫn sẽ được liên kết mặc dù không còn cách nào để xây dựng nó nữa. bên trong
trong tương lai, makepp có thể sẽ tự động nhận ra tình huống này và loại trừ nó khỏi
danh sách ký tự đại diện, nhưng hiện tại, bạn phải yêu cầu nó loại trừ nó theo cách thủ công:

chương trình: $ (only_targets * .o)
$ (CC) $ (đầu vào) -o $ (đầu ra)

Makepp không biết bất kỳ cách nào để xây dựng cái cũ .o bất kỳ tệp nào nữa vì tệp nguồn của nó là
đã biến mất, vì vậy hàm "$ (only_targets)" sẽ loại trừ nó khỏi danh sách phụ thuộc.

Lời khuyên cho nhiều thư mục
Một trong những lý do chính để viết makepp là để đơn giản hóa việc xử lý nhiều
các thư mục. Makepp có thể kết hợp các lệnh xây dựng từ nhiều tệp trang, vì vậy nó có thể
xử lý đúng một quy tắc trong một tệp makefile phụ thuộc vào tệp được tạo bởi
makefile khác nhau.

Điều gì đến do in nơi of đệ quy làm cho

Makepp hỗ trợ tạo đệ quy để tương thích ngược, nhưng nó rất được khuyến khích
rằng bạn không sử dụng nó. Nếu bạn không biết nó là gì, tốt.

Xem "Hệ thống tốt hơn cho các bản dựng phân cấp" trong makepp để biết chi tiết về lý do bạn không muốn
sử dụng đệ quy make, hoặc tìm kiếm "đệ quy làm cho được coi là có hại" trên web.

Thay vì thực hiện một lệnh đệ quy để tạo mục tiêu "tất cả" trong mọi tệp cấu hình, nó là
thường dễ dàng hơn để cho makepp tìm ra mục tiêu nào sẽ thực sự cần được xây dựng.
Hơn nữa, nếu bạn đặt tất cả .o và các tệp thư viện trong cùng một thư mục với
makefiles, sau đó makepp sẽ tự động tìm ra những makefiles nào cũng cần thiết -
chỉ có điều cần thiết là yêu cầu cấp cao nhất của bạn liệt kê các tệp cần thiết
cho bước liên kết cuối cùng. Xem các ví dụ bên dưới.

Một trang điểm cho mỗi danh mục: với ngầm tải

Cách phổ biến nhất để xử lý nhiều thư mục là đặt một tệp makefile trong mỗi thư mục
trong đó mô tả cách xây dựng mọi thứ trong hoặc từ thư mục đó. Nếu bạn đặt .o các tập tin trong
cùng thư mục với các tệp nguồn, sau đó tải ngầm (xem "Tải ngầm" trong
makepp_build_algorithm) sẽ tự động tìm tất cả các tệp makefiles. Nếu bạn đặt của bạn .o
các tệp trong một thư mục khác (ví dụ: trong một thư mục con phụ thuộc vào kiến ​​trúc), thì bạn
có thể sẽ phải tải tất cả các tệp trang có liên quan bằng cách sử dụng câu lệnh "load_makefile".

Đây là một mẫu makefile cấp cao nhất cho hệ thống phân cấp thư mục sử dụng tính năng tải ngầm
để xây dựng một chương trình bao gồm nhiều thư viện được chia sẻ (nhưng hãy xem "Bạn có thực sự cần một
thư viện? "trong makepp_cookbook, bởi vì tạo một chương trình từ một loạt các thư viện được chia sẻ
không nhất thiết phải là một ý kiến ​​hay):

# Makefile cấp cao nhất:
chương trình: main.o ** / *. la # Liên kết trong các thư viện được chia sẻ từ tất cả các thư mục con.
$ (LIBTOOL) --mode = link $ (CC) $ (CFLAGS) $ (đầu vào) -o $ (đầu ra) $ (LIBS)

Đó là khá nhiều tất cả những gì bạn cần trong makefile cấp cao nhất. Trong mỗi thư mục con, bạn
có thể sẽ làm một cái gì đó như thế này:

# Makefile trong mỗi thư mục con:
bao gồm standard_defs.mk # Searches., .., ../ .., v.v. cho đến khi nó
# tìm tệp bao gồm được chỉ định.
# ghi đè một số định nghĩa biến ở đây
ĐẶC BIỆT_FLAGS: = -do_something_dierence

Mỗi makefile có thể khá giống nhau nếu các lệnh để xây dựng các mục tiêu
khá giống nhau.

Cuối cùng, bạn sẽ đặt những điều sau vào tiêu chuẩn_defs.mk tệp (có lẽ nên
được đặt trong thư mục cấp cao nhất):

# Cài đặt biến chung và xây dựng quy tắc cho tất cả các thư mục.
CFLAGS: = -g -O2
INCLUDE_DIR: = $ (find_upwards bao gồm)
# Tìm kiếm., .., ../ .., v.v. cho một tệp hoặc
# thư mục được gọi là bao gồm, vì vậy nếu bạn đặt
# tất cả các tệp bao gồm của bạn trong đó, điều này sẽ
# tìm họ.
BAO GỒM: = -I $ (INCLUDE_DIR)

% .lo:% .c
$ (LIBTOOL) --mode = biên dịch $ (CC) $ (CFLAGS) $ (BAO GỒM) -c $ (đầu vào) -o $ (đầu ra)

lib $ (rel_to., ..). la: $ (only_targets * .lo)
$ (LIBTOOL) --mode = link $ (CC) $ (CFLAGS) -o $ (đầu ra) $ (đầu vào)
# $ (rel_to., ..) trả về tên của hiện tại
# thư mục con liên quan đến cấp trên
# thư mục con. Vì vậy, nếu makefile này là xyz / Makefile,
# quy tắc này sẽ xây dựng xyz / libxyz.la.

# Xuất bản công khai các tệp bao gồm vào thư mục bao gồm cấp cao nhất:
$ (INCLUDE_DIR) / public _%. H: public _%. H
: build_check symlnk
& ln -fr $ (đầu vào) $ (đầu ra)

Một trang điểm cho mỗi danh mục: rõ ràng tải

Nếu bạn muốn đặt tất cả .o các tệp vào một thư mục con phụ thuộc vào kiến ​​trúc, sau đó
ví dụ trên nên được sửa đổi thành một cái gì đó như thế này:

# Makefile cấp cao nhất:
MAKEFILES: = $ (ký tự đại diện ** / Makeppfile) # Danh sách tất cả các thư mục con để
# lấy trang điểm từ.

load_makefile $ (MAKEFILES) # Tải tất cả chúng vào.

include standard_defs.mk # Nhận lệnh biên dịch cho main.o.

chương trình: $ (ARCH) /main.o * / ** / $ (ARCH) / *. la
$ (LIBTOOL) --mode = link $ (CC) $ (CFLAGS) $ (đầu vào) -o $ (đầu ra) $ (LIBS)
# * / ** / $ (ARCH) loại trừ thư mục con
# $ (ARCH), nơi chúng tôi không muốn xây dựng
# một thư viện được chia sẻ.

Mỗi makefile sẽ giống hệt như trước đây:

# Makefile trong mỗi thư mục con:
bao gồm standard_defs.mk
# ... ghi đè biến ở đây

Và cuối cùng, tiêu chuẩn_defs.mk sẽ chứa một cái gì đó như sau:

# Cài đặt biến chung và xây dựng quy tắc cho tất cả các thư mục.
ARCH; = $ (shell uname -s) - $ (shell uname -m) - $ (shell uname -r)
# Đôi khi mọi người chỉ sử dụng $ (shell uname -m), nhưng
# điều này sẽ giống nhau đối với FreeBSD và Linux trên
# an x86. -R không thực sự hữu ích trên Linux,
# nhưng quan trọng đối với các hệ điều hành khác: mã nhị phân cho
# SunOS 5.8 thường không chạy trên SunOS 5.7.
& mkdir -p $ (ARCH) # Đảm bảo rằng thư mục đầu ra tồn tại.
CFLAGS: = -g -O2
INCLUDE_DIR: = $ (find_upwards bao gồm)
# Tìm kiếm., .., ../ .., v.v. cho một tệp hoặc
# thư mục được gọi là bao gồm, vì vậy nếu bạn đặt
# tất cả các tệp bao gồm của bạn trong đó, điều này sẽ
# tìm họ.
BAO GỒM: = -I $ (INCLUDE_DIR)

$ (ARCH) /%. Lo:% .c
$ (LIBTOOL) --mode = biên dịch $ (CC) $ (CFLAGS) $ (BAO GỒM) -c $ (đầu vào) -o $ (đầu ra)

$ (ARCH)/ lib$ (rel_to., ..). la: $ (only_targets * .lo)
$ (LIBTOOL) --mode = link $ (CC) $ (CFLAGS) -o $ (đầu ra) $ (đầu vào)
# $ (rel_to., ..) trả về tên của hiện tại
# thư mục con liên quan đến cấp trên
# thư mục con. Vì vậy, nếu makefile này là xyz / Makefile,
# quy tắc này sẽ xây dựng xyz / $ (ARCH) /libxyz.la.

# Sao chép tệp bao gồm công khai vào thư mục bao gồm cấp cao nhất:
$ (INCLUDE_DIR) / public _%. H: public _%. H
& cp $ (đầu vào) $ (đầu ra)

Tự động chế tạo các trang điểm

Nếu trang điểm của bạn đều cực kỳ giống nhau (như trong ví dụ trên), bạn có thể nói với Makepp
để xây dựng chúng tự động nếu chúng không tồn tại. Chỉ cần thêm phần sau vào cấp cao nhất của bạn
tạo tập tin:

SUBDIRS: = $ (bộ lọc_out không mong muốn_dir1 không mong muốn_dir2, $ (ký tự đại diện * / **))
$ (foreach) / Makeppfile:: foreach $ (SUBDIRS)
& echo "bao gồm standard_defs.mk" -o $ (đầu ra)
& echo "_include add_defs.mk" -o >> $ (đầu ra)
# Nếu tệp bổ sung_defs.mk tồn tại, thì
# nó sẽ được bao gồm, nhưng nếu nó không tồn tại,
# câu lệnh _include sẽ bị bỏ qua.

Bây giờ bản thân các tệp makefiles sẽ được tự động xây dựng.

Một trang điểm có thể at các hàng đầu cấp

Nếu tất cả các tệp trang điểm của bạn giống hệt nhau, bạn có thể hỏi: tại sao tôi phải có một tệp trang điểm ở mỗi
cấp độ? Tại sao không đưa tất cả những thứ đó vào makefile cấp cao nhất?

Có, điều này có thể được thực hiện. Nhược điểm chính là nó trở nên khó xác định hơn
các tùy chọn xây dựng khác nhau cho từng thư mục con. Một bất lợi thứ hai là
makefile có thể sẽ trở nên khó đọc hơn một chút.

Đây là một ví dụ về việc đó:

# Makefile cấp cao nhất cho hệ thống phân cấp thư mục. Xây dựng chương trình
# trong số một tập hợp các thư viện được chia sẻ làm ví dụ. (Xem lưu ý ở trên
# vì lý do tại sao bạn có thể muốn sử dụng liên kết gia tăng hoặc một số
# phương pháp tiếp cận thay vì thư viện được chia sẻ.)
makepp_percent_subdirs: = 1 # Cho phép% khớp nhiều thư mục.
SUBDIRS: = $ (filter_out * CVS * other-wish_dirs $ (ký tự đại diện **))
CFLAGS: = -g -O2
BAO GỒM: = -bao gồm

% .lo:% .c
$ (LIBTOOL) --mode = biên dịch $ (CC) $ (BAO GỒM) $ (CFLAGS) -c $ (đầu vào) -o $ (đầu ra)

$ (foreach)/ lib$ (notdir $ (foreach)). la: $ (foreach) / *. lo: foreach $ (SUBDIRS)
$ (LIBTOOL) --mode = link $ (CC) $ (CFLAGS) -o $ (đầu ra) $ (đầu vào)
# Quy tắc tạo tất cả các thư viện.

chương trình: main.o ** / *. la
$ (LIBTOOL) --mode = link $ (CC) $ (CFLAGS) -o $ (đầu ra) $ (đầu vào)

bao gồm / $ (notdir $ (foreach)): $ (foreach): foreach ** / public _ *. h
& cp $ (đầu vào) $ (đầu ra)
# Quy tắc mẫu để sao chép công khai
# tệp .h có thể truy cập vào đúng vị trí.

A giống cá lăng mục tiêu

Các tệp trang điểm truyền thống chứa một mục tiêu sạch, cho phép xóa mọi thứ đã
được xây dựng. Có ba lý do tại sao bạn không nên làm điều này với makepp:

1. Makepp đi rất lâu để đảm bảo một bản dựng chính xác. Vì vậy, tuyệt vọng "tôi không
biết điều gì sai ”, khiến bạn muốn làm lại từ đầu đã là dĩ vãng.

2. Mọi người đôi khi sẽ cố gắng tiết kiệm thời gian bằng cách làm hai việc trái ngược nhau cùng một lúc:
"làm cho sạch tất cả". Điều này có thể làm nhầm lẫn hệ thống ký tự đại diện thông minh của makepp, vì nó sẽ
trước tiên hãy hiểu sự thật trước khi làm bất cứ điều gì. Sau đó, đến hành động sạch sẽ,
không nói cho makepp biết nó làm gì (thực sự nó không thể, bởi vì nó hoàn tác một cái gì đó -
trái với công cụ xây dựng dùng để làm gì). Sau đó đến "tất cả", nhưng các tệp cập nhật,
mà ở đó, đã biến mất một cách bí ẩn.

3. Có lệnh "makeppclean", thực hiện điều tương tự và hiệu quả hơn.

Tuy nhiên, chúng tôi giữ lại phần lịch sử này, vì nó cho bạn biết điều gì đó về
cách makepp hoạt động: Một mục tiêu giả mạo được gọi là "sạch" chỉ là tên cho một tập hợp các lệnh
xóa tất cả các tệp là kết quả của quá trình tạo. Thường thì một mục tiêu sạch sẽ
đại loại như thế này:

$ (sạch rởm):
& rm -fm $ (ký tự đại diện * .o .makepp_log)
# -m và .makepp_log loại bỏ tất cả những thứ tạp nham của makepp.

Thay vì liệt kê rõ ràng các tệp bạn muốn xóa, bạn cũng có thể yêu cầu makepp
xóa mọi thứ mà nó biết cách xây dựng, như thế này:

$ (sạch rởm):
& rm -fm .makepp_log $ (only_targets *)

Điều này có lợi thế là nếu bất kỳ tệp nguồn nào của bạn có thể được tạo từ các tệp khác,
chúng cũng sẽ bị xóa; mặt khác, cũ .o tệp (tệp từng là
có thể xây dựng nhưng tệp nguồn của nó đã bị xóa kể từ đó) sẽ không bị xóa.

Nếu bạn có một bản dựng liên quan đến các tệp makefiles trong một số thư mục khác nhau, thì phần đầu của bạn-
makefile cấp có thể tham chiếu đến mục tiêu "sạch" (hoặc bất kỳ mục tiêu giả mạo nào khác) trong một mục tiêu khác
tạo tập tin:

# Makefile cấp cao nhất
SUBDIRS: = sub1 sub2

# xây dựng quy tắc tại đây

# Dọn dẹp sau khi xây dựng:
$ (sạch giả): $ (SUBDIRS) / sạch
& rm -fm .makepp_log $ (only_targets *)

Ngoài ra, bạn có thể chỉ đặt mục tiêu "sạch" của mình trong makefile cấp cao nhất và có
xử lý tất cả các thư mục, như thế này:

$ (sạch rởm):
& rm -fm $ (only_targets ** / *)

Sử dụng Qt's sức mạnh bộ tiền xử lý
Ví dụ này cho thấy một makefile cho một tiện ích sử dụng thư viện GUI Qt của Nokia (xem
<http://qt.nokia.com>). Điều duy nhất hơi bất thường về điều này là bạn
phải chạy bộ tiền xử lý có tên "moc" trên hầu hết các tệp ".h" có chứa định nghĩa tiện ích con,
nhưng bạn không muốn chạy "moc" trên bất kỳ tệp ".h" nào không sử dụng macro "Q_OBJECT".

Tự động xác định cái nào các tập tin nhu cầu sức mạnh các tập tin

Tất nhiên, bạn có thể chỉ cần liệt kê tất cả các tệp ".h" cần để "moc" chạy trên chúng.
Tuy nhiên, nếu bạn đang nhanh chóng phát triển các tiện ích con mới, nó có thể gây phiền toái cho
tiếp tục cập nhật danh sách trong makefile. Bạn có thể nhận được xung quanh nhu cầu để liệt kê moc
mô-đun rõ ràng với một cái gì đó như thế này:

MOC: = $ (QTDIR) / bin / moc
MODULES: = bất kỳ mô-đun nào bạn tình cờ có trong chương trình của mình
MOC_MODULES: = $ (patsubst% .h, moc_%, $ (& grep -l / Q_OBJECT / * .h))
# Quét tất cả các tệp .h cho macro Q_OBJECT.

my_program: $ (MODULES) .o $ (MOC_MODULES) .o
$ (CXX) $ (đầu vào) -o $ (đầu ra)

moc _%. cxx:% .h # Tạo tệp moc từ tệp .h.
$ (MOC) $ (đầu vào) -o $ (đầu ra)

% .o:% .cxx
$ (CXX) $ (CXXFLAGS) -c $ (đầu vào) -o $ (đầu ra)

Phương pháp này quét từng .h các tệp mỗi khi makepp được chạy, tìm kiếm
Macro "Q_OBJECT". Điều này nghe có vẻ tốn kém, nhưng có lẽ sẽ không mất nhiều thời gian. (Các .h
tất cả các tệp sẽ phải được tải từ đĩa bằng quá trình biên dịch, vì vậy chúng sẽ
được lưu vào bộ nhớ đệm.)

#include các .moc hồ sơ

Một cách tiếp cận khác là "#include" đầu ra từ bộ xử lý trước "moc" trong tiện ích con của bạn
tập tin thực hiện. Điều này có nghĩa là bạn phải nhớ viết "#include", nhưng nó có
lợi thế là có ít mô-đun hơn để biên dịch, và do đó, quá trình biên dịch diễn ra nhanh hơn.
(Đối với hầu hết quá trình biên dịch C ++, phần lớn thời gian được dành để đọc các tệp tiêu đề và
đầu ra từ bộ xử lý trước cần bao gồm gần như nhiều tệp như tiện ích con của bạn
dù sao.) Ví dụ:

// my_widget.h
lớp MyWidget: QWidget công cộng {
Q_ĐỐI TƯỢNG
//...
}

// my_widget.cpp

#include "my_widget.h"
#include "my_widget.moc" // my_widget.moc là kết quả đầu ra từ
// bộ tiền xử lý moc.
// Những thứ thực hiện khác ở đây.
MyWidget :: MyWidget (QWidget * cha, const char * name):
QWidget (cha mẹ, tên)
{
//...
}

Bây giờ bạn cần có một quy tắc trong makefile của mình để tạo tất cả các tệp ".moc", như sau:

MOC: = $ (QTDIR) / bin / moc
# Quy tắc tạo tệp .moc:
% .moc:% .h
$ (MOC) $ (đầu vào) -o $ (đầu ra)

Makepp đủ thông minh để nhận ra rằng nó cần tạo "my_widget.moc" nếu không
đã tồn tại, hoặc nếu nó đã lỗi thời.

Cách tiếp cận thứ hai này là cách mà tôi thường sử dụng vì nó tăng tốc độ biên dịch.

Thay thế cho phản đối làm cho thành ngữ
KIẾM MỤC TIÊU

Đôi khi mọi người có các quy tắc trong makefile của họ phụ thuộc vào mục tiêu mà họ đang xây dựng,
bằng cách sử dụng biến đặc biệt "MAKECMDGOALS". Ví dụ, đôi khi người ta thấy những thứ như
điều này:

ifneq ($ (sản xuất bộ lọc, $ (MAKECMDGOALS)),)
CFLAGS: = -O2
khác
CFLAGS: = -g
endif

Điều này sẽ hoạt động tốt với makepp. Tuy nhiên, tôi khuyên bạn không nên sử dụng "MAKECMDGOALS" cho những
các trường hợp (và GNU cũng đưa ra hướng dẫn sử dụng). Tốt hơn hết bạn nên đặt và
biên dịch gỡ lỗi .o các tệp trong các thư mục riêng biệt hoặc đặt cho chúng các tiền tố khác nhau hoặc
các hậu tố, hoặc sử dụng kho lưu trữ, để giữ chúng riêng biệt.

Có lẽ lần duy nhất bạn thực sự muốn tham khảo "MAKECMDGOALS" là nếu nó
mất nhiều thời gian để tải trang điểm của bạn và bạn không cần điều đó cho mục tiêu "sạch" của mình
(nhưng bạn không cần mục tiêu sạch). Ví dụ,

ifneq ($ (MAKECMDGOALS), sạch)
load_makefile $ (ký tự đại diện ** / Makeppfile)
khác
no_implicit_load. # Ngăn chặn tự động tải bất kỳ cấu hình nào khác.
endif

$ (sạch rởm):
& rm -f $ (ký tự đại diện ** / *. o)

Đệ quy làm cho đến xây dựng in khác nhau thư mục

Xem "Mẹo cho nhiều thư mục" trong makepp_cookbook.

Đệ quy làm cho đến thay đổi giá trị of a biến

Một số makefiles tự gọi lại bằng một giá trị khác của một biến, ví dụ: debug
target trong đoạn makefile sau

.PHONY: gỡ lỗi tất cả

tối ưu hóa:
Chương trình $ (MAKE) CFLAGS = -O2

gỡ lỗi:
Chương trình $ (MAKE) CFLAGS = -g

chương trình: ao bo
$ (CC) $ (CFLAGS) $ ^ -o $ @

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

Nếu người dùng nhập "make debug", nó sẽ xây dựng chương trình ở chế độ mặc định với tính năng gỡ lỗi được bật
thay vì tối ưu hóa.

Một cách tốt hơn để làm điều đó là xây dựng hai chương trình khác nhau, với hai bộ
các tệp đối tượng, như thế này:

CFLAGS: = -O2
DEBUG_FLAGS: = -g
CÁC CHẾ ĐỘ: = ab

chương trình: $ (MODULES) .o
$ (CC) $ (CFLAGS) $ (đầu vào) -o $ (đầu ra)

debug / program: debug / $ (MODULES) .o
$ (CC) $ (DEBUG_FLAGS) $ (đầu vào) -o $ (đầu ra)

% .o:% .c
$ (CC) $ (CFLAGS) -c $ (đầu vào) -o $ (đầu ra)

gỡ lỗi /%. o:% .c
$ (CC) $ (DEBUG_FLAGS) -c $ (đầu vào) -o $ (đầu ra)

$ (gỡ lỗi giả): gỡ lỗi / chương trình

Ưu điểm của việc làm theo cách này là (a) bạn không cần phải xây dựng lại mọi thứ khi bạn
chuyển từ gỡ lỗi sang tối ưu hóa và quay lại lần nữa; (NS)

Phần trên có thể được viết ngắn gọn hơn bằng cách sử dụng kho. Sau
makefile hoàn toàn tương đương:

gỡ lỗi kho lưu trữ =. # Làm cho thư mục con gỡ lỗi trông giống như một bản sao của
# thư mục con hiện tại.
load_makefile gỡ lỗi CFLAGS = -g
# Ghi đè CFLAGS khi được gọi trong thư mục con gỡ lỗi
CFLAGS: = -O2 # Giá trị của CFLAGS khi được gọi trong thư mục con này

chương trình: ao bo
$ (CC) $ (CFLAGS) $ ^ -o $ @

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

$ (gỡ lỗi giả): gỡ lỗi / chương trình
# Nếu người dùng nhập "makepp debug", bản dựng
# gỡ lỗi / chương trình thay vì chương trình.

hỗn hợp lời khuyên
Độ đáng tin của do I xây dựng một một phần khác nhau chỉ Một lần?

Makepp làm cho điều này khó thực hiện vì kết quả không phù hợp với các quy tắc.
Nhưng có những tình huống mà bạn có thể cần điều này, ví dụ: chỉ biên dịch một mô-đun với
thông tin gỡ lỗi nặng. Bạn có thể đạt được điều này trong hai bước bằng cách đầu tiên xây dựng
phụ thuộc một cách riêng biệt, và sau đó loại trừ nó khỏi giai đoạn liên kết:

makepp DEBUG = 3 buggy.o # Xây dựng nó bằng tùy chọn khác.
makepp --dont-build = buggy.o buggy # Sử dụng nó, bất chấp tùy chọn xây dựng "sai".

Độ đáng tin của do I làm cho chắc chắn my đầu ra thư mục hiện hữu?

Bạn có thể chỉ định một quy tắc để tạo thư mục đầu ra, sau đó đảm bảo rằng mỗi tệp
đi trong thư mục đầu ra phụ thuộc vào nó. Nhưng thường dễ dàng hơn khi làm những việc như
điều này:

# Cách cổ điển
dummy: = $ (shell test -d $ (OUTPUT_DIRECTORY) || mkdir -p $ (OUTPUT_DIRECTORY))
# Điều này thường dễ dàng hơn so với việc làm cho tất cả các tệp phụ thuộc vào
# $ (OUTPUT_DIRECTORY) và có quy tắc để thực hiện.
# Lưu ý rằng bạn phải sử dụng: = thay vì = để buộc nó phải
# thực thi ngay lập tức.
# Một cách tiếp cận thay thế: sử dụng mã Perl, OUTPUT_DIRECTORY var cục bộ
perl_bắt đầu
-d $ OUTPUT_DIRECTORY hoặc mkdir $ OUTPUT_DIRECTORY;
perl_end
# Cách hiện đại, không làm gì cho các thư mục hiện có
& mkdir -p $ (OUTPUT_DIRECTORY)

Một trong những câu lệnh này phải ở gần đầu trang makefile của bạn, để chúng được thực thi
trước bất cứ thứ gì có thể cần đến thư mục.

Độ đáng tin của do I lực lượng a lệnh đến thi hành on mỗi xây dựng?

Cách dễ nhất là hoàn toàn không sử dụng cơ chế quy tắc, mà chỉ đơn giản là thực thi nó, như
điều này:

dummy: = $ (shell date> last_build_timestamp)

Hoặc đặt nó trong một khối perl, như thế này:

perl_bắt đầu
system ("lệnh thực thi");
perl_end

Cách tiếp cận này có nhược điểm là nó sẽ được thực thi ngay cả khi mục tiêu không liên quan
đang được chạy.

Cách tiếp cận thứ hai là khai báo tệp là một mục tiêu giả mạo, ngay cả khi nó là một tệp thật.
Điều này sẽ buộc makepp thực hiện lại lệnh để xây dựng nó mọi lúc, nhưng chỉ khi nó
xuất hiện trong danh sách phụ thuộc của một số quy tắc.

Độ đáng tin của do I rút ngắn các hiển thị xây dựng lệnh?

Thường thì có rất nhiều tùy chọn cho các lệnh biên dịch mà những gì được hiển thị trên
màn hình không thể đọc được. Bạn có thể thay đổi những gì được hiển thị bằng cách tắt hiển thị
toàn bộ lệnh, và sau đó in ra một cách rõ ràng phần thú vị của lệnh. nó là
dễ dàng chỉ in phần có liên quan của lệnh bằng cách sử dụng "$ (filter_out)", như
điều này:

ALL_CFLAGS = $ (CFLAGS) $ (BAO GỒM) $ (ADDL_CXX_FLAGS) $ (DEBUG_FLAGS)

% .o:% .c
@ & echo $ (notdir $ (CC)) ... \
$ (filter_out -I * $ (ADDL_CXX_FLAGS), $ (ALL_CFLAGS)) \
-c $ (đầu vào)
@ $ (CC) $ (ALL_CFLAGS) -c $ (đầu vào) -o $ (đầu ra)

(Dấu "@" phía trước lệnh ngăn chặn việc in ra lệnh.)

Điều này sẽ cho phép bạn xem hầu hết các tùy chọn thú vị nhưng sẽ không hiển thị tất cả
bao gồm các thư mục (trong số đó thường có rất nhiều!). Nếu phần bạn quan tâm
in liền kề trong lệnh của bạn, bạn cũng có thể sử dụng chức năng "in" (chức năng này thêm
dòng mới, vì vậy bạn không muốn một vài trong số chúng):

Mục tiêu:
@ ... $ (in phần thú vị) ...

Độ đáng tin của do I chuyển đổi a hồ sơ trong phụ thuộc?

Đối với một số định dạng tệp khó hiểu, việc triển khai máy quét không đáng giá. Trong một dự án
chúng tôi có các tệp xml, nói foobar.xml trong đó chứa các phụ thuộc cho foobar.out:


Một
NS
NS


Chúng tôi quyết định tuân theo bố cục đơn giản này, vì vậy chúng tôi không cần phải phân tích cú pháp xml. Với
nội trang & sed, đây là những gì chúng tôi làm với ba sự thay thế đơn giản cho ba loại
dòng:

% .d:% .xml
& sed 's! ! $ (gốc) .out: \\! || NS! (. +) ! $$ 1 \\! || NS! !# Trống!' \
$ (đầu vào) -o $ (đầu ra)

bao gồm foobar.d

Cố gắng bao gồm điều này, trước tiên hãy tạo "foobar.d":

foobar.out: \
Một \
NS \
NS \
# Trống

Dòng trống (chỉ là nhận xét hoặc thực sự trống) tránh phải lo lắng về dấu vết
dấu gạch chéo ngược. Một giải pháp thay thế tạo ra một danh sách nhiều dòng là:

% .d:% .xml
& sed 's! ! $ (gốc) .out: \ $$ ((! || s! !))! || s! <. +?> !! g '\
$ (đầu vào) -o $ (đầu ra)

bao gồm foobar.d

Điều này tạo ra một tương đương:

foobar.out: $ ((
a
b
c
))

Nếu bạn phải viết lại phức tạp hơn, hãy xác định một hàm trong makefile hoặc trong
mô-đun mà bạn bao gồm. Ví dụ: undefining $ _ sẽ bỏ qua các dòng nhập:

bộ lọc phụ của tôi {
trả về undef $ _ nếu /
$ gốc của tôi = f_stem;
NS! ! $ stem.out: \ $ ((! || s! !))! || s! <. +?> !! g;
}

% .d:% .xml
& sed 's! ! $ (gốc) .out: \ $$ ((! || s! !))! || s! <. +?> !! g '\
$ (đầu vào) -o $ (đầu ra)

bao gồm foobar.d

Sử dụng makepp_cookbook trực tuyến bằng các dịch vụ onworks.net


Máy chủ & Máy trạm miễn phí

Tải xuống ứng dụng Windows & Linux

Lệnh Linux

Ad