2009-02-03 38 views
46

Tôi đang viết một Makefile với rất nhiều công cụ lặp đi lặp lại, ví dụ:Chức năng trong Makefile

debug_ifort_Linux: 
     if [ $(UNAME) = Linux ]; then       \ 
      $(MAKE) FC=ifort FFLAGS=$(difort) PETSC_FFLAGS="..." \ 
        [email protected] LEXT="ifort_$(UNAME)" -e syst;  \ 
     else             \ 
      echo $(err_arch);          \ 
      exit 1;            \ 
     fi 

nơi mục tiêu 'Syst' được định nghĩa, biến 'uname' được định nghĩa (và thường là Linux, nhưng có thể cũng bởi Cygwin hay OSF1) và các biến 'difort' và 'err_arch' cũng được xác định . Khối mã này được sử dụng rất nhiều lần cho các mục tiêu trình biên dịch khác nhau (sử dụng quy ước tên là ''). Vì đây là một lượng lớn mã dự phòng, tôi muốn có thể viết nó một cách đơn giản hơn. Ví dụ: tôi muốn thực hiện một việc như sau:

debug_ifort_Linux: 
     compile(uname,compiler,flags,petsc_flags,target,lext) 

nơi biên dịch có thể là một hàm làm mã ở trên dựa trên các đối số. Có ai có bất kỳ ý tưởng làm thế nào tôi có thể thực hiện điều này?

Trả lời

35

Có 3 khái niệm liên quan:

  1. call function
  2. multi-line variables
  3. conditionals

Kết quả refactored có thể trông như thế này:

ifeq ($(UNAME),Linux) 
    compile = $(MAKE) FC=$(1) FFLAGS=$(2) PETSC_FFLAGS=$(3) \ 
         [email protected] LEXT="$(1)_$(UNAME)" -e syst 
else 
    define compile = 
     echo $(err_arch) 
     exit 1 
    endef 
endif 


debug_ifort: 
     $(call compile,ifort,$(difort),"...") 

Đó là \ còn lại là tiếp tục dòng $(MAKE) cho vỏ. Không có biến nhiều dòng là cần thiết ở đây, bởi vì nó chỉ là một dòng mã shell. Biến nhiều dòng chỉ được sử dụng trong khối khác.

Nếu bạn không cần tham số mà bạn có thể sử dụng: = phân công và chỉ mở rộng phương pháp này với $(compile) (xem canned recipes)

[Chỉnh sửa]Lưu ý: Sử dụng làm trước khi phiên bản 3,82, các = đã không được công nhận ở cuối câu lệnh xác định cho tôi. Tôi đã sửa lỗi này bằng cách sử dụng define compile để thay thế.

+0

Tại sao điều này tốt hơn câu trả lời trước đó hiện được đánh dấu là chính xác? –

+1

Bạn nên sử dụng các biến nhiều dòng, thay vì \. Mà một lần nữa sẽ là "quá nhiều để chỉ cần chỉnh sửa câu trả lời đó" (như xa như tôi nhận được đánh giá cho đến nay) – JonnyJD

+0

Và giải thích các biến multiline là một chút quá nhiều cho một bình luận. Nhưng tất nhiên bạn không phải đồng ý. – JonnyJD

36

Bạn đang tìm kiếm call function.

compile =             \ 
     if [ $(UNAME) = $(1) ]; then      \ 
      $(MAKE) FC=$(2) FFLAGS=$(3) PETSC_FFLAGS="..." \ 
        [email protected] LEXT="$(4)_$(UNAME)" -e syst; \ 
     else            \ 
      echo $(err_arch);        \ 
      exit 1;           \ 
     fi 

debug_ifort_Linux: 
     $(call compile,Linux,ifort,$(difort),ifort) 

Nếu bạn có thể cơ cấu lại Makefile của bạn một chút, tuy nhiên, bạn nên xem nếu bạn có thể sử dụng make 's conditionals thay vì sh' s.

+1

Cảm ơn, điều này đã hiệu quả! :) Tôi không nhìn thấy trực tiếp làm thế nào tôi có thể sử dụng điều kiện của thực hiện để làm giống như những gì tôi muốn. Ít nhất là không có một _lot_ của tái cơ cấu. Tất nhiên, điều này có thể chỉ vì tôi không có nhiều kinh nghiệm với viết Makefiles ... –

+0

Đây là một ví dụ điển hình, nơi bạn nên sử dụng [biến nhiều dòng] (http://www.gnu.org/software/make /manual/html_node/Multi_002dLine.html). – JonnyJD