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 allyazılarak makeçağrılır ve hedefi çağırır ./build/Makefile.
Hedefin ./build/Makefileyaptığı ilk şey, değişken olan builddizini 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 -pbuild-pmkdir
Hedefin ./build/Makefileyaptığı ikinci şey, dizinleri dizine değiştirmek buildve çağırmaktır cmake.
allHedefe geri dönersek $(MAKE) -C build, $(MAKE)otomatik olarak oluşturulan bir Makefile değişkeni nerede olur make. make -Cherhangi bir şey yapmadan önce dizini değiştirir. Bu nedenle, kullanmak $(MAKE) -C buildyapmakla eşdeğerdir cd build; make.
Özetlemek gerekirse, bu Makefile sarmalayıcısını make allveya makeile eşdeğer olarak adlandırmak:
mkdir build
cd build
cmake ..
make
Hedef distcleançağırır cmake .., sonra make -C build cleanve son olarak, tüm içerikleri kaldırır builddizine. 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 cleanve 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 rmparç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 buildveya 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 cmaketutarlı 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 .