Tạo một biến trong makefile bằng cách đọc nội dung của một tệp khác


81

Làm cách nào để tôi có thể tạo một biến ngay lập tức từ makefile, giá trị của biến này sẽ là toàn bộ nội dung của một tệp dữ liệu khác.

Câu trả lời:


49

Tôi đoán rằng bạn muốn đặt một biến trong Makefile của mình thành nội dung của một tệp khác:

FILE=test.txt
VARIABLE=`cat $(FILE)`

target:
    echo $(VARIABLE)

3
Trên thực tế, tôi không thể đặt định nghĩa VARIABLE trên tất cả: bởi vì PATH_TO_MY_DATA_FILE không tồn tại cho đến khi một số lệnh được chạy trong all: target. Để thay thế, những gì tôi đã làm là tôi đã chia mọi thứ thành hai tệp trang điểm (đã tạo một tệp phụ) và khai báo BIẾN TẦN ở đầu tệp phụ và bây giờ nó hoạt động giống như một chiếc bùa.
Srinath

26
Đây là một câu trả lời sai. Giá trị của VARIABLElà một chuỗi cat $(FILE)(trong dấu ngoặc kép) chỉ được mở rộng trong một công thức bởi shell. Hãy thử in giá trị của nó như thế nào $(info ${VARIABLE}).
Maxim Egorushkin

3
@MaximEgorushkin Quả không sai. Bạn chỉ cần coi VARIABLEnhư một lời hứa. Đây là phiên bản duy nhất hoạt động với các phiên bản cũ hơn của make. Cả hai :=$(shell ...)đều là phần mở rộng GNU.
thúc

7
Bị phản đối. Điều này sẽ thực thi catmỗi khi quy tắc được thực thi. Điều này thường không được dự kiến ​​và cần được cảnh báo, vì nó chậm. Ngoài ra, nếu tập tin là một đường ống, nó có tác dụng phụ không mong muốn. Việc gán phải được thực hiện với :=để quy tắc sẽ không được đánh giá khi biến được thay thế nhưng khi biến được xác định. Giá trị thay thế phải là $(shell cat $(FILE))để catlệnh được thực thi tại chỗ bởi make, không phải sau đó bởi các quy tắc công thức.
Christian Hujer

2
@antred, make là một phần của bộ công cụ UNIX / POSIX tiêu chuẩn, cũng bao gồm cat. Nếu bạn cài đặt thì việc cài đặt tất cả các công cụ cơ bản khác là điều bình thường và có rất ít trường hợp gây khó khăn. Việc dựa vào catcác quy tắc thay thế phức tạp thay vì phức tạp sẽ làm cho các tệp trang điểm của bạn dễ hiểu hơn nhiều và gần như có thể di động hoặc đôi khi di động hơn.
Michael

81

Giả sử GNU thực hiện:

file := whatever.txt
variable := $(shell cat ${file})

4
@ceving Sử dụng tạo GNU tiêu chuẩn. Solaris make là một ứng dụng không di động.
Maxim Egorushkin

7
Gnu make không tiêu chuẩn và cũng không dễ di động hơn solaris make. "Phổ biến" là từ của bạn. Nếu chúng ta nghiêm túc xem xét tính di động và cấu hình tiêu chuẩn, hãy gắn bó với posix.
把 友情 留 在 无 盐

3
Tôi muốn chọn "Phổ biến" trong trường hợp này - Make không phải GNU chỉ là quá sơ khai. Nếu bạn đang muốn tiếp tục hỗ trợ các hệ điều hành của những năm 1990, thì câu trả lời của @ bb-Generation có lẽ là thứ bạn cần (mặc dù nó sẽ khiến bạn gặp rắc rối trong nhiều trường hợp). Trong tất cả các trường hợp khác, GNU Make có thể dễ dàng sử dụng hoặc - nhiều khả năng hơn - là mặc định, vì vậy hãy tận dụng nó.
Guss

1
GNU make chạy ở mọi nơi nên có, nó dễ di động hơn nhiều so với bất kỳ công cụ nào khác. "tiêu chuẩn" có thể là chủ quan, được cấp.
MarcH

26

GNU make phiên bản 4.2 hỗ trợ thao tác đọc tệp, vì vậy đối với câu trả lời tuyệt vời của Maxim Egorushkin , hiện có một cách tùy chọn để giải quyết vấn đề này:

FILE     := test.txt
variable :=$(file < $(FILE))

Đã sửa một lỗi. Tên biến phân biệt chữ hoa chữ thường. Các tên 'foo', 'FOO' và 'Foo' đều đề cập đến các biến khác nhau. ( gnu.org/software/make/manual/html_node/Using-Variables.html )
Yaroslav Nikitenko

dấu ngoặc kép cũng không cần thiết, $ (file <"$ (FILE)") cố gắng mở "test.txt".
cagney, 27/09/19

14

catkhông tồn tại trên Windows. Giải pháp hoạt động cho Linux và Windows:

cat := $(if $(filter $(OS),Windows_NT),type,cat)
variable := $(shell $(cat) filename)

Giải thích: Có vẻ như trên Windows luôn có OSbiến môi trường được định nghĩa bằng 'Windows_NT'. Theo cách này, typelệnh cho Windows được sử dụng, cho không phải Windows catđược sử dụng.


9

Đơn giản hơn nhiều kể từ khi $(file op filename)được thêm vào:

VARIABLE = $(file < my_file.txt)

Trang hướng dẫn sử dụng tại đây: https://www.gnu.org/software/make/manual/html_node/File-Function.html#index-file_002c-reading-from


1
Điều này làm việc cho tôi dưới dạng GNU Make 4.2.1, không giống như các giải pháp đề nghị khác :)
TabeaKischka

3
Điều này đã được giới thiệu trong GNU Make 4, và hệ điều hành MacOS vẫn tàu với 3,81 vào năm 2019 :-(
MichielB

4

Nếu bạn đang sử dụng GNU make, một cách khác để có được hiệu ứng này là sử dụng make "include" của một makefile khác:

Từ Makefile:

include "./MyFile.mak"

Tạo tệp "MyFile.mak" với nội dung:

FILE := "my file content"
FILE += "more content 1"
FILE += "more content 2"

điều này có vẻ không hiệu quả, tôi hiểuMakefile:1: "./MyFile.mak": No such file or directory
knocte

điều đó có thể có nghĩa là bạn đang sử dụng phiên bản GNU không có của make .... hoặc phiên bản thực sự cũ của GNU make ... hãy thử: "make -v"
Bill Moore

sử dụng make in mac, không chắc được gói hoặc cài đặt bằng homebrew, make -vchoGNU Make 3.81
knocte

bạn có đảm bảo rằng bạn không vô tình chuyển đổi các ký tự TAB thành ký tự SPACE trong Makefile không? Về mặt này, Make gần như khó chịu như python.
Bill Moore

Tôi đã nhận này để làm việc bởi trên máy Mac của tôi bằng cách loại bỏ các dấu ngoặc kép, ví dụ: include ./MyFile
Charlie Trần

3

Vì nền tảng chưa được chỉ định, đây là cách nó hoạt động trên Solaris:

VERSION:sh = cat VERSION

all:
        echo $(VERSION)

0

Đây là một giải pháp di động hơn, hoạt động với MAKEphiên bản 3, khi filekhông có chỉ thị. Nhược điểm là nó yêu cầu tạo một tệp tạm thời trong quá trình này.

$(shell echo define my_variable > file.tmp)
$(shell cat my_file.txt >> file.tmp)
$(shell echo endef >> file.tmp)
include file.tmp

Ý tưởng chính là sử dụng definechỉ thị, được thiết kế đặc biệt để khai báo các biến đa dòng. Tất nhiên, bạn có thể tránh sử dụng shellvà một tệp tạm thời nếu bạn có thể ghi rõ ràng nội dung tệp để sử dụng Makefile.

Hãy nhớ rằng, nếu tệp của bạn chứa $các dấu hiệu, MAKEsẽ cố gắng mở rộng chúng dưới dạng các biến / chỉ thị khi my_variableđược mở rộng (hoặc khi được gán, bạn định nghĩa nó bằng :=). Nếu bạn muốn tránh nó, bạn cần phải thoát khỏi chúng trước khi đưa vào nội dung tệp. Ví dụ, thay vì catbạn có thể làm điều này:

$(shell sed 's/\$$/$$$$/g' my_file.txt >> file.tmp)
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.