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õ makevà gọi mục tiêu ./build/Makefile.
Điều đầu tiên mà mục tiêu ./build/Makefilethực hiện là tạo buildthư mục bằng cách sử dụng $(MKDIR), đây là một biến cho mkdir -p. Thư mục buildlà 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 mkdirkhô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/Makefilelàm là thay đổi thư mục vào buildthư mục và gọi cmake.
Quay lại allmục tiêu, chúng tôi gọi $(MAKE) -C build, $(MAKE)biến Makefile được tạo tự động ở đâu make. make -Cthay đổi thư mục trước khi làm bất cứ điều gì. Do đó, sử dụng $(MAKE) -C buildlà 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 allhoặc maketương đương với việc thực hiện:
mkdir build
cd build
cmake ..
make
Mục tiêu distcleangọi cmake .., sau đó make -C build clean, và cuối cùng, loại bỏ tất cả nội dung khỏi buildthư 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 buildtrướ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 buildthư 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 rmnhư một phần của distcleanmụ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 buildhoặ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 cmakemộ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 ++ .