Một giải pháp mà tôi tìm thấy gần đây là kết hợp khái niệm xây dựng ngoài nguồn với trình bao bọc Makefile.
Trong tệp CMakeLists.txt cấp cao nhất của tôi, tôi bao gồm các mục sau để ngăn các bản dựng trong nguồn:
if ( ${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR} )
message( FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt." )
endif()
Sau đó, tôi tạo một Makefile cấp cao nhất và bao gồm các mục sau:
# -----------------------------------------------------------------------------
# CMake project wrapper Makefile ----------------------------------------------
# -----------------------------------------------------------------------------
SHELL := /bin/bash
RM := rm -rf
MKDIR := mkdir -p
all: ./build/Makefile
@ $(MAKE) -C build
./build/Makefile:
@ ($(MKDIR) build > /dev/null)
@ (cd build > /dev/null 2>&1 && cmake ..)
distclean:
@ ($(MKDIR) build > /dev/null)
@ (cd build > /dev/null 2>&1 && cmake .. > /dev/null 2>&1)
@- $(MAKE) --silent -C build clean || true
@- $(RM) ./build/Makefile
@- $(RM) ./build/src
@- $(RM) ./build/test
@- $(RM) ./build/CMake*
@- $(RM) ./build/cmake.*
@- $(RM) ./build/*.cmake
@- $(RM) ./build/*.txt
ifeq ($(findstring distclean,$(MAKECMDGOALS)),)
$(MAKECMDGOALS): ./build/Makefile
@ $(MAKE) -C build $(MAKECMDGOALS)
endif
Mục tiêu mặc định all
được gọi bằng cách gõ make
và gọi mục tiêu ./build/Makefile
.
Điều đầu tiên mà mục tiêu ./build/Makefile
thực hiện là tạo build
thư mục bằng cách sử dụng $(MKDIR)
, đây là một biến cho mkdir -p
. Thư mục build
là nơi chúng tôi sẽ thực hiện việc xây dựng ngoài nguồn. Chúng tôi cung cấp đối số -p
để đảm bảo rằng mkdir
không hét lên với chúng tôi vì đã cố gắng tạo một thư mục có thể đã tồn tại.
Điều thứ hai mục tiêu ./build/Makefile
làm là thay đổi thư mục vào build
thư mục và gọi cmake
.
Quay lại all
mục tiêu, chúng tôi gọi $(MAKE) -C build
, $(MAKE)
biến Makefile được tạo tự động ở đâu make
. make -C
thay đổi thư mục trước khi làm bất cứ điều gì. Do đó, sử dụng $(MAKE) -C build
là tương đương với làm cd build; make
.
Để tóm tắt, hãy gọi trình bao bọc Makefile này bằng make all
hoặc make
tương đương với việc thực hiện:
mkdir build
cd build
cmake ..
make
Mục tiêu distclean
gọi cmake ..
, sau đó make -C build clean
, và cuối cùng, loại bỏ tất cả nội dung khỏi build
thư mục. Tôi tin rằng đây chính xác là những gì bạn yêu cầu trong câu hỏi của bạn.
Phần cuối cùng của Makefile sẽ đánh giá xem mục tiêu do người dùng cung cấp có hay không distclean
. Nếu không, nó sẽ thay đổi thư mục thành build
trước khi gọi nó. Điều này rất mạnh bởi vì người dùng có thể gõ, ví dụ make clean
, và Makefile sẽ biến nó thành tương đương cd build; make clean
.
Tóm lại, trình bao bọc Makefile này, kết hợp với cấu hình CMake xây dựng ngoài nguồn bắt buộc, làm cho nó để người dùng không bao giờ phải tương tác với lệnh cmake
. Giải pháp này cũng cung cấp một phương thức thanh lịch để loại bỏ tất cả các tệp đầu ra CMake khỏi build
thư mục.
PS Trong Makefile, chúng tôi sử dụng tiền tố @
để chặn đầu ra từ lệnh shell và tiền tố @-
để bỏ qua lỗi từ lệnh shell. Khi sử dụng rm
như một phần của distclean
mục tiêu, lệnh sẽ trả về lỗi nếu các tệp không tồn tại (chúng có thể đã bị xóa bằng cách sử dụng dòng lệnh với rm -rf build
hoặc chúng không bao giờ được tạo ở vị trí đầu tiên). Lỗi trả về này sẽ buộc Makefile của chúng ta thoát. Chúng tôi sử dụng tiền tố @-
để ngăn chặn điều đó. Có thể chấp nhận nếu một tệp đã bị xóa; chúng tôi muốn Makefile của chúng tôi tiếp tục và loại bỏ phần còn lại.
Một điều cần lưu ý: Makefile này có thể không hoạt động nếu bạn sử dụng một số lượng biến CMake khác nhau để xây dựng dự án của bạn, ví dụ , cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar"
. Makefile này giả định rằng bạn gọi CMake theo cách nhất quán, bằng cách nhập cmake ..
hoặc bằng cách cung cấp cmake
một số lượng đối số nhất quán (mà bạn có thể đưa vào Makefile của mình).
Cuối cùng, tín dụng nơi tín dụng đến hạn. Trình bao bọc Makefile này được điều chỉnh từ Makefile được cung cấp bởi Mẫu dự án ứng dụng C ++ .