2013-03-07 41 views
8

Tôi mới đến CMake và tôi có một vấn đề mà tôi không thể tìm ra một giải pháp. Tôi đang sử dụng CMake để biên dịch một dự án với một loạt các thư mục con tùy chọn và nó xây dựng các tệp thư viện được chia sẻ như mong đợi. Phần đó dường như hoạt động tốt. Mỗi thư mục con này chứa một tệp sql. Tôi cần phải concat tất cả các tập tin sql được chọn vào một tập tin tiêu đề sql và cài đặt kết quả. Vì vậy, một tập tin như:Sử dụng CMake, làm thế nào tôi có thể concat tập tin và cài đặt chúng

sql_header.sql 
sub_dir_A.sql 
sub_dir_C.sql 
sub_dir_D.sql 

Nếu tôi đã làm điều này trực tiếp trong một làm cho tập tin tôi có thể làm điều gì đó như sau chỉ thông minh hơn để đối phó với chỉ tiểu dirs chọn:

cat sql_header.sql > "${INSTALL_PATH}/somefile.sql" 
cat sub_dir_A.sql >> "${INSTALL_PATH}/somefile.sql" 
cat sub_dir_C.sql >> "${INSTALL_PATH}/somefile.sql" 
cat sub_dir_D.sql >> "${INSTALL_PATH}/somefile.sql" 

Tôi có loại đã tìm ra các phần của điều này, như tôi có thể sử dụng:

LIST(APPEND PACKAGE_SQL_FILES "some_file.sql") 

mà tôi cho rằng tôi có thể đặt trong mỗi tệp phụ tệp CMakeLists.txt để thu thập tên tệp. Và tôi có thể tạo macro như:

CAT(IN "${PACKAGE_SQL_FILES}" OUT "${INSTALL_PATH}/somefile.sql") 

Nhưng tôi bị mất giữa thời điểm ban đầu CMake chạy và khi nó chạy từ cài đặt thực hiện. Có lẽ có một cách tốt hơn để làm điều này. Tôi cần điều này để làm việc trên cả Windows và Linux.

Tôi sẽ hài lòng với một số gợi ý để hướng tôi đi đúng hướng.

Trả lời

10

Bạn có thể tạo tệp nối được chủ yếu bằng cách sử dụng các lệnh filefunction của CMake.

Đầu tiên, tạo một hàm cat:

function(cat IN_FILE OUT_FILE) 
    file(READ ${IN_FILE} CONTENTS) 
    file(APPEND ${OUT_FILE} "${CONTENTS}") 
endfunction() 

Giả sử bạn có một danh sách các tập tin đầu vào trong biến PACKAGE_SQL_FILES, bạn có thể sử dụng chức năng như thế này:

# Prepare a temporary file to "cat" to: 
file(WRITE somefile.sql.in "") 

# Call the "cat" function for each input file 
foreach(PACKAGE_SQL_FILE ${PACKAGE_SQL_FILES}) 
    cat(${PACKAGE_SQL_FILE} somefile.sql.in) 
endforeach() 

# Copy the temporary file to the final location 
configure_file(somefile.sql.in somefile.sql COPYONLY) 

Lý do để viết tạm thời là vì vậy tệp đích thực chỉ được cập nhật nếu nội dung của nó đã thay đổi. Xem this answer vì lý do tại sao đây là một điều tốt.

Bạn nên lưu ý rằng nếu bạn đang bao gồm các thư mục con thông qua lệnh add_subdirectory, tất cả các subdir đều có phạm vi riêng của chúng theo các biến CMake có liên quan. Trong các subdirs, sử dụng list sẽ chỉ ảnh hưởng đến các biến trong phạm vi của subdir đó.

Nếu bạn muốn tạo danh sách có sẵn trong phạm vi gốc, bạn sẽ cần sử dụng set(... PARENT_SCOPE), ví dụ:

set(PACKAGE_SQL_FILES 
    ${PACKAGE_SQL_FILES} 
    ${CMAKE_CURRENT_SOURCE_DIR}/some_file.sql 
    PARENT_SCOPE) 

Tất cả điều này cho đến nay chỉ đơn giản là tạo tệp nối trong gốc của cây xây dựng của bạn. Để cài đặt nó, bạn có thể muốn sử dụng install(FILES ...) lệnh:

install(FILES ${CMAKE_BINARY_DIR}/somefile.sql 
     DESTINATION ${INSTALL_PATH}) 

Vì vậy, bất cứ khi nào CMake chạy (hoặc bởi vì bạn tự gọi nó hay vì nó phát hiện những thay đổi khi bạn "làm cho"), nó sẽ cập nhật các nối tập tin trong cây xây dựng. Chỉ khi bạn chạy "make install" thì cuối cùng tập tin sẽ được sao chép từ gốc xây dựng đến vị trí cài đặt.

+0

Sử dụng tốt cấu hình_file ... ;-) – DLRdave

+0

Cảm ơn, điều này rất hữu ích.Đó là khó khăn để có được kết quả để bong bóng lên nếu bạn có nhiều thư mục ở nhiều độ sâu, nhưng tôi đã nhận nó để làm việc bằng cách sử dụng gợi ý rất hữu ích của bạn. Cảm ơn! –

+0

Tôi đã thử điều này, và nó làm việc ... trừ khi tập tin có dấu chấm phẩy, tại thời điểm đó nó không thành công vì dấu chấm phẩy âm thầm tước ra. Đây là kết quả bình thường của dấu chấm phẩy là dấu phân tách danh sách trong cmake. Trường hợp thử nghiệm đơn giản nhất cho thấy vấn đề là 'tập (NỘI DUNG" a; b; c \ n ") tệp (WRITE out.txt $ {CONTENTS})' Bản sửa lỗi là nội dung báo giá khi viết, ví dụ: '" $ {CONTENTS} "' –

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