Câu trả lời:
Tiết lộ đầy đủ: Ban đầu tôi thích cách tiếp cận toàn cầu vì tính đơn giản của nó, nhưng qua nhiều năm tôi đã nhận ra rằng việc liệt kê rõ ràng các tệp ít bị lỗi đối với các dự án lớn, nhiều nhà phát triển.
Câu trả lời gốc:
Những lợi thế của Globing là:
Thật dễ dàng để thêm các tệp mới vì chúng chỉ được liệt kê ở một nơi: trên đĩa. Không Globing tạo ra sự trùng lặp.
Tệp CMakeLists.txt của bạn sẽ ngắn hơn. Đây là một điểm cộng lớn nếu bạn có nhiều tệp. Không toàn cầu khiến bạn mất logic CMake giữa các danh sách tệp khổng lồ.
Ưu điểm của việc sử dụng danh sách tệp được mã hóa cứng là:
CMake sẽ theo dõi chính xác các phụ thuộc của một tệp mới trên đĩa - nếu chúng ta sử dụng toàn cầu thì các tệp không được đặt vòng đầu tiên khi bạn chạy CMake sẽ không được chọn
Bạn đảm bảo rằng chỉ các tệp bạn muốn được thêm vào. Globbing có thể nhận các tập tin đi lạc mà bạn không muốn.
Để khắc phục sự cố đầu tiên, bạn chỉ cần "chạm" vào CMakeLists.txt có toàn cầu, bằng cách sử dụng lệnh cảm ứng hoặc bằng cách viết tệp mà không thay đổi. Điều này sẽ buộc CMake chạy lại và chọn tệp mới.
Để khắc phục vấn đề thứ hai, bạn có thể sắp xếp mã của mình một cách cẩn thận vào các thư mục, đây là điều bạn có thể làm dù sao đi nữa. Trong trường hợp xấu nhất, bạn có thể sử dụng list(REMOVE_ITEM)
lệnh để dọn sạch danh sách các tập tin toàn cầu:
file(GLOB to_remove file_to_remove.cpp)
list(REMOVE_ITEM list ${to_remove})
Tình huống thực tế duy nhất mà điều này có thể cắn bạn là nếu bạn đang sử dụng một cái gì đó như git-bisect để thử các phiên bản cũ hơn của mã của bạn trong cùng thư mục bản dựng. Trong trường hợp đó, bạn có thể phải dọn dẹp và biên dịch nhiều hơn mức cần thiết để đảm bảo bạn có được các tệp đúng trong danh sách. Đây là một trường hợp góc như vậy, và một trong những nơi bạn đã ở trên ngón chân của mình, rằng nó không thực sự là một vấn đề.
Simply "touch" the CMakeLists.txt
là OK nếu bạn là nhà phát triển, nhưng đối với những người khác xây dựng phần mềm của bạn nó thực sự có thể là một nỗi đau-điểm đó xây dựng của bạn thất bại sau khi cập nhật và gánh nặng trên chúng để điều tra tại sao.
Cách tốt nhất để xác định các tệp nguồn trong CMake là liệt kê chúng một cách rõ ràng .
Bản thân những người tạo ra CMake khuyên không nên sử dụng Globing.
Xem: https://cmake.org/cmake/help/v3.15/command/file.html?highlight=glob#file
(Chúng tôi không khuyên bạn nên sử dụng GLOB để thu thập danh sách các tệp nguồn từ cây nguồn của bạn. Nếu không có tệp CMakeLists.txt thay đổi khi một nguồn được thêm hoặc xóa thì hệ thống xây dựng được tạo không thể biết khi nào nên yêu cầu CMake tạo lại.)
Tất nhiên, bạn có thể muốn biết những nhược điểm là gì - đọc tiếp!
Nhược điểm lớn đối với toàn cầu là việc tạo / xóa các tệp sẽ không tự động cập nhật hệ thống xây dựng.
Nếu bạn là người thêm các tệp, điều này có vẻ như là một sự đánh đổi chấp nhận được, tuy nhiên điều này gây ra vấn đề cho những người khác xây dựng mã của bạn, họ cập nhật dự án từ kiểm soát phiên bản, chạy bản dựng, sau đó liên hệ với bạn, phàn nàn rằng
"bản dựng bị hỏng".
Để làm cho vấn đề tồi tệ hơn, lỗi thường đưa ra một số lỗi liên kết không đưa ra bất kỳ gợi ý nào cho nguyên nhân của vấn đề và thời gian bị mất để khắc phục sự cố.
Trong một dự án tôi đã làm việc, chúng tôi đã bắt đầu phát triển toàn cầu nhưng đã nhận được rất nhiều khiếu nại khi các tệp mới được thêm vào, đó là lý do đủ để liệt kê rõ ràng các tệp thay vì toàn cầu hóa.
Điều này cũng phá vỡ các luồng công việc git phổ biến
( git bisect
và chuyển đổi giữa các nhánh tính năng).
Vì vậy, tôi không thể khuyến nghị điều này, những vấn đề mà nó gây ra vượt xa sự tiện lợi, khi ai đó không thể xây dựng phần mềm của bạn vì điều này, họ có thể mất nhiều thời gian để theo dõi vấn đề hoặc chỉ từ bỏ.
Và một lưu ý khác, Chỉ cần nhớ chạm vào CMakeLists.txt
không phải lúc nào cũng đủ, với các bản dựng tự động sử dụng toàn cầu, tôi phải chạy cmake
trước mỗi bản dựng vì các tệp có thể đã được thêm / xóa kể từ bản dựng trước *.
Có những thời điểm mà Globing thích hợp hơn:
CMakeLists.txt
tệp cho các dự án hiện tại không sử dụng CMake. cmake
để tạo tệp xây dựng mỗi lần để có bản dựng đáng tin cậy / chính xác (đi ngược lại ý định của CMake - khả năng phân tách cấu hình khỏi tòa nhà) .* Có, tôi có thể đã viết một mã để so sánh cây tập tin trên đĩa trước và sau khi cập nhật, nhưng đây không phải là một cách giải quyết tốt và một cái gì đó tốt hơn để lại cho hệ thống xây dựng.
Trong CMake 3.12, các lệnh file(GLOB ...)
vàfile(GLOB_RECURSE ...)
lệnh đã đạt được một CONFIGURE_DEPENDS
tùy chọn chạy lại cmake nếu giá trị của toàn cầu thay đổi. Vì đó là nhược điểm chính của việc tạo khối cho các tệp nguồn, giờ đây bạn có thể làm như vậy:
# Whenever this glob's value changes, cmake will rerun and update the build with the
# new/removed files.
file(GLOB_RECURSE sources CONFIGURE_DEPENDS "*.cpp")
add_executable(my_target ${sources})
Tuy nhiên, một số người vẫn khuyên bạn nên tránh Globing cho các nguồn. Thật vậy, tài liệu nêu rõ:
Chúng tôi không khuyên bạn nên sử dụng GLOB để thu thập danh sách các tệp nguồn từ cây nguồn của bạn. ...
CONFIGURE_DEPENDS
Cờ có thể không hoạt động đáng tin cậy trên tất cả các máy phát hoặc nếu một máy phát mới được thêm vào trong tương lai không thể hỗ trợ nó, các dự án sử dụng nó sẽ bị kẹt. Ngay cả khiCONFIGURE_DEPENDS
hoạt động đáng tin cậy, vẫn có một chi phí để thực hiện kiểm tra trên mỗi lần xây dựng lại.
Cá nhân, tôi xem xét các lợi ích của việc không phải quản lý thủ công danh sách tệp nguồn để vượt trội hơn các nhược điểm có thể có. Nếu bạn phải chuyển trở lại các tệp được liệt kê thủ công, điều này có thể dễ dàng đạt được bằng cách chỉ cần in danh sách nguồn toàn cầu và dán lại.
Bạn có thể an toàn toàn cầu (và có lẽ nên) với chi phí của một tệp bổ sung để giữ các phụ thuộc.
Thêm các chức năng như thế này ở đâu đó:
# Compare the new contents with the existing file, if it exists and is the
# same we don't want to trigger a make by changing its timestamp.
function(update_file path content)
set(old_content "")
if(EXISTS "${path}")
file(READ "${path}" old_content)
endif()
if(NOT old_content STREQUAL content)
file(WRITE "${path}" "${content}")
endif()
endfunction(update_file)
# Creates a file called CMakeDeps.cmake next to your CMakeLists.txt with
# the list of dependencies in it - this file should be treated as part of
# CMakeLists.txt (source controlled, etc.).
function(update_deps_file deps)
set(deps_file "CMakeDeps.cmake")
# Normalize the list so it's the same on every machine
list(REMOVE_DUPLICATES deps)
foreach(dep IN LISTS deps)
file(RELATIVE_PATH rel_dep ${CMAKE_CURRENT_SOURCE_DIR} ${dep})
list(APPEND rel_deps ${rel_dep})
endforeach(dep)
list(SORT rel_deps)
# Update the deps file
set(content "# generated by make process\nset(sources ${rel_deps})\n")
update_file(${deps_file} "${content}")
# Include the file so it's tracked as a generation dependency we don't
# need the content.
include(${deps_file})
endfunction(update_deps_file)
Và sau đó đi toàn cầu:
file(GLOB_RECURSE sources LIST_DIRECTORIES false *.h *.cpp)
update_deps_file("${sources}")
add_executable(test ${sources})
Bạn vẫn đang xoay quanh các phụ thuộc rõ ràng (và kích hoạt tất cả các bản dựng tự động!) Như trước đây, chỉ có trong hai tệp thay vì một.
Thay đổi duy nhất trong thủ tục là sau khi bạn đã tạo một tệp mới. Nếu bạn không toàn cầu, quy trình làm việc là sửa đổi CMakeLists.txt từ bên trong Visual Studio và xây dựng lại, nếu bạn làm toàn cầu, bạn sẽ chạy cmake một cách rõ ràng - hoặc chỉ cần chạm vào CMakeLists.txt.
make
lỗi liên kết lạ.
Chỉ định từng tệp riêng lẻ!
Tôi sử dụng CMakeLists.txt thông thường và tập lệnh python để cập nhật nó. Tôi chạy tập lệnh python bằng tay sau khi thêm tập tin.
Xem câu trả lời của tôi ở đây: https://stackoverflow.com/a/48318388/3929196