วิธีแก้ปัญหาที่ฉันพบเมื่อเร็ว ๆ นี้คือการรวมแนวคิดการสร้าง out-of-source กับตัวห่อ Makefile
ในไฟล์ CMakeLists.txt ระดับบนสุดของฉันฉันรวมสิ่งต่อไปนี้เพื่อป้องกันการสร้างในแหล่งที่มา:
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()
จากนั้นฉันสร้าง Makefile ระดับบนสุดและรวมสิ่งต่อไปนี้:
# -----------------------------------------------------------------------------
# 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
เป้าหมายเริ่มต้นall
ถูกเรียกโดยการพิมพ์และเรียกเป้าหมายmake
./build/Makefile
สิ่งแรกที่เป้าหมาย./build/Makefile
ไม่สามารถที่จะสร้างbuild
ไดเรกทอรีใช้ซึ่งเป็นตัวแปรสำหรับ$(MKDIR)
mkdir -p
ไดเรกทอรีbuild
เป็นที่ที่เราจะดำเนินการสร้างนอกแหล่งที่มาของเรา เราให้ข้อโต้แย้ง-p
เพื่อให้แน่ใจmkdir
ว่าไม่ได้กรีดร้องที่เราสำหรับการสร้างไดเรกทอรีที่อาจมีอยู่แล้ว
สิ่งที่สองเป้าหมาย./build/Makefile
ไม่สามารถที่จะไดเรกทอรีเปลี่ยนแปลงไดเรกทอรีและเรียกbuild
cmake
กลับไปที่all
เป้าหมายที่เราเรียก$(MAKE) -C build
ที่$(MAKE)
เป็นตัวแปร Makefile make
สร้างโดยอัตโนมัติสำหรับ make -C
เปลี่ยนไดเรกทอรีก่อนทำอะไร ดังนั้นการใช้เทียบเท่ากับการทำ$(MAKE) -C build
cd build; make
ในการสรุปการโทร Makefile wrapper นี้ด้วยmake all
หรือmake
เทียบเท่ากับการทำ:
mkdir build
cd build
cmake ..
make
เป้าหมายdistclean
จะเรียกใช้cmake ..
จากนั้นmake -C build clean
และสุดท้ายจะลบเนื้อหาทั้งหมดออกจากbuild
ไดเรกทอรี ฉันเชื่อว่านี่เป็นสิ่งที่คุณต้องการในคำถามของคุณ
ชิ้นสุดท้ายของ Makefile distclean
ประเมินถ้าเป้าหมายที่ผู้ใช้ให้เป็นหรือไม่ ถ้าไม่มันจะเปลี่ยนไดเรกทอรีเป็นbuild
ก่อนที่จะเรียกมัน นี้จะมีประสิทธิภาพมากเพราะผู้ใช้สามารถพิมพ์ตัวอย่างเช่นmake clean
และ Makefile cd build; make clean
จะเปลี่ยนที่เป็นเทียบเท่าของ
สรุปนี้เสื้อคลุม Makefile ในการรวมกันกับออกจากแหล่งที่มาของการสร้างการกำหนดค่า CMake cmake
บังคับให้มันเพื่อให้ผู้ใช้ไม่เคยมีการโต้ตอบกับคำสั่ง โซลูชันนี้ยังให้วิธีการที่ยอดเยี่ยมในการลบไฟล์เอาต์พุต CMake ทั้งหมดออกจากbuild
ไดเรกทอรี
PS ใน Makefile เราใช้ส่วนนำหน้า@
เพื่อยับยั้งเอาต์พุตจากคำสั่งเชลล์และส่วนนำหน้า@-
เพื่อละเว้นข้อผิดพลาดจากคำสั่งเชลล์ เมื่อใช้rm
เป็นส่วนหนึ่งของdistclean
เป้าหมายคำสั่งจะส่งคืนข้อผิดพลาดหากไม่มีไฟล์อยู่ (ไฟล์เหล่านั้นอาจถูกลบไปแล้วโดยใช้บรรทัดคำสั่งด้วยrm -rf build
หรือไม่เคยถูกสร้างขึ้นมาก่อน) ข้อผิดพลาดในการส่งคืนนี้จะบังคับให้ Makefile ของเราออก เราใช้ส่วนนำหน้า@-
เพื่อป้องกันสิ่งนั้น เป็นที่ยอมรับหากไฟล์ถูกลบไปแล้ว เราต้องการให้ Makefile ของเราดำเนินต่อไปและนำส่วนที่เหลือออกไป
อีกสิ่งหนึ่งที่จะต้องทราบ: นี่ Makefile อาจไม่ทำงานถ้าคุณใช้จำนวนตัวแปรของตัวแปร CMake cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar"
ที่จะสร้างโครงการของคุณตัวอย่างเช่น Makefile นี้สมมติว่าคุณเรียกใช้ CMake ด้วยวิธีที่สอดคล้องกันไม่ว่าจะโดยการพิมพ์cmake ..
หรือโดยcmake
ระบุจำนวนอาร์กิวเมนต์ที่สอดคล้องกัน (ซึ่งคุณสามารถรวมไว้ใน Makefile ของคุณ)
ในที่สุดเครดิตที่ครบกำหนดเครดิต นี้เสื้อคลุม Makefile ดัดแปลงมาจาก Makefile ที่มีให้โดยโปรแกรมประยุกต์ c ++ โครงการแม่แบบ