Son zamanlarda bulduğum bir çözüm, kaynak dışı derleme konseptini Makefile sarıcı ile birleştirmektir.
Üst düzey CMakeLists.txt dosyamda, kaynak içi derlemeleri önlemek için aşağıdakileri ekliyorum:
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()
Sonra, bir üst düzey Makefile oluşturmak ve aşağıdakileri dahil:
# -----------------------------------------------------------------------------
# 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
Varsayılan hedef all
yazılarak make
çağrılır ve hedefi çağırır ./build/Makefile
.
Hedefin ./build/Makefile
yaptığı ilk şey, değişken olan build
dizini oluşturmaktır . Dizin , kaynak dışı derlememizi gerçekleştireceğimiz yerdir. Zaten var olabilecek bir dizin oluşturmaya çalıştığımız için bize çığlık atmamasını sağlamak için argüman sağlıyoruz .$(MKDIR)
mkdir -p
build
-p
mkdir
Hedefin ./build/Makefile
yaptığı ikinci şey, dizinleri dizine değiştirmek build
ve çağırmaktır cmake
.
all
Hedefe geri dönersek $(MAKE) -C build
, $(MAKE)
otomatik olarak oluşturulan bir Makefile değişkeni nerede olur make
. make -C
herhangi bir şey yapmadan önce dizini değiştirir. Bu nedenle, kullanmak $(MAKE) -C build
yapmakla eşdeğerdir cd build; make
.
Özetlemek gerekirse, bu Makefile sarmalayıcısını make all
veya make
ile eşdeğer olarak adlandırmak:
mkdir build
cd build
cmake ..
make
Hedef distclean
çağırır cmake ..
, sonra make -C build clean
ve son olarak, tüm içerikleri kaldırır build
dizine. Sorunuzda tam olarak istediğiniz bu olduğuna inanıyorum.
Makefile'nin son parçası, kullanıcı tarafından sağlanan hedefin olup olmadığını değerlendirir distclean
. Değilse, build
çağırmadan önce dizinleri değiştirir . Bu çok güçlü çünkü kullanıcı örneğin yazabilir make clean
ve Makefile bunu eşdeğerine dönüştürecektir cd build; make clean
.
Sonuç olarak, bu Makefile sarıcı, zorunlu bir kaynak dışı derleme CMake yapılandırması ile birlikte, kullanıcının komutla asla etkileşime girmemesi için bunu yapar cmake
. Bu çözüm ayrıca tüm CMake çıktı dosyalarını dizinden kaldırmak için zarif bir yöntem sağlar build
.
PS Makefile'de, @
bir kabuk komutundan çıktıyı bastırmak için önekini ve bir kabuk komutundan @-
hataları yoksaymak için önekini kullanırız. Hedefin bir rm
parçası olarak kullanıldığında distclean
, dosyalar yoksa komut bir hata döndürür (komut satırı kullanılarak zaten silinmiş olabilir rm -rf build
veya ilk etapta hiç oluşturulmamış olabilir). Bu dönüş hatası Makefile'mızı çıkmaya zorlayacaktır. Bunu @-
önlemek için öneki kullanıyoruz . Bir dosyanın zaten kaldırılmış olması kabul edilebilir; Makefile'mizin devam etmesini ve gerisini kaldırmasını istiyoruz.
Dikkat edilmesi gereken başka bir şey: Örneğin, projenizi oluşturmak için değişken sayıda CMake değişkeni kullanırsanız bu Makefile çalışmayabilir cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar"
. Bu Makefile, CMake'i yazarak cmake ..
veya cmake
tutarlı sayıda argüman (Makefile'nize ekleyebileceğiniz) sağlayarak tutarlı bir şekilde çağırdığınızı varsayar .
Son olarak, kredi vadesi gelen kredi. Bu Makefile sarmalayıcısı, C ++ Application Project Template tarafından sağlanan Makefile'den uyarlanmıştır .