Buat direktori output / build

116

Saya cukup baru mengenal CMake, dan membaca beberapa tutorial tentang cara menggunakannya, dan menulis beberapa 50 baris skrip CMake yang rumit untuk membuat program untuk 3 kompiler yang berbeda. Ini mungkin menyimpulkan semua pengetahuan saya di CMake.

Sekarang masalah saya adalah saya memiliki beberapa kode sumber, yang foldernya tidak ingin saya sentuh / ubah ketika saya membuat program. Saya ingin semua makefile dan folder CMake dan output masuk ../Compile/, jadi saya mengubah beberapa variabel dalam skrip CMake saya untuk itu, dan itu berfungsi beberapa saat ketika saya melakukan sesuatu seperti ini di laptop saya:

Compile$ cmake ../src
Compile$ make

Dimana dengan itu saya memiliki keluaran bersih di folder tempat saya berada sekarang, itulah yang saya cari.

Sekarang saya pindah ke komputer lain, dan mengkompilasi ulang CMake 2.8.11.2, dan saya hampir kembali ke titik awal! Itu selalu mengkompilasi sesuatu ke dalam srcfolder tempat saya CMakeLists.txtberada.

Bagian di mana saya memilih direktori di skrip CMake saya adalah ini:

set(dir ${CMAKE_CURRENT_SOURCE_DIR}/../Compile/)
set(EXECUTABLE_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
set(LIBRARY_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dir})
set(CMAKE_BUILD_FILES_DIRECTORY ${dir})
set(CMAKE_BUILD_DIRECTORY ${dir})
set(CMAKE_BINARY_DIR  ${dir})
SET(EXECUTABLE_OUTPUT_PATH ${dir})
SET(LIBRARY_OUTPUT_PATH ${dir}lib)
SET(CMAKE_CACHEFILE_DIR ${dir})

Dan sekarang selalu diakhiri dengan:

-- Build files have been written to: /.../src

Apakah saya melewatkan sesuatu?

Fisikawan Kuantum
sumber
4
Ada sedikit kebutuhan untuk mengatur semua variabel yang Anda tetapkan. CMake menetapkannya ke default yang wajar. Anda sebaiknya tidak memodifikasi CMAKE_BINARY_DIRatau CMAKE_CACHEFILE_DIR. Apa yang terjadi jika Anda menghapus semua set()panggilan ini dan melakukannya cd Compile; rm -rf *; cmake ../src?
Angew tidak lagi bangga dengan SO
5
Pada dasarnya, selama Anda berada di luar direktori sumber saat menjalankan CMake, itu tidak akan mengubah direktori sumber kecuali CMakeList Anda secara eksplisit memberitahukannya.
Angew tidak lagi bangga dengan SO
@Angew Terima kasih atas tipnya, yang mengejutkan! Saya menghapus semua baris itu dan hanya menggunakan cmake ../src dan itu bekerja dengan sangat baik! Ini sangat mengejutkan karena saya mencobanya sebelumnya ketika saya pertama kali belajar CMake dan tidak berhasil. Berikan jawaban Anda dalam balasan resmi untuk memberi Anda tanda centang yang besar :)
Ahli Fisika Kuantum
1
Yang menyelamatkan saya adalah pernyataan @Adam Bowen bahwa "Anda tidak dapat membuat build out-of-source untuk direktori sumber dengan build dalam-sumber"
Aur Saraf

Jawaban:

60

Ada sedikit kebutuhan untuk mengatur semua variabel yang Anda tetapkan. CMake menetapkannya ke default yang wajar. Anda sebaiknya tidak memodifikasi CMAKE_BINARY_DIRatau CMAKE_CACHEFILE_DIR. Perlakukan ini sebagai hanya baca.

Pertama hapus file cache bermasalah yang ada dari direktori src:

cd src
rm CMakeCache.txt
cd ..

Kemudian hapus semua set()perintah dan lakukan:

cd Compile
rm -rf *
cmake ../src

Selama Anda berada di luar direktori sumber saat menjalankan CMake, CMake tidak akan mengubah direktori sumber kecuali CMakeList Anda secara eksplisit memerintahkannya.

Setelah Anda memiliki ini berfungsi, Anda dapat melihat di mana CMake menempatkan sesuatu secara default, dan hanya jika Anda tidak puas dengan lokasi default (seperti nilai default EXECUTABLE_OUTPUT_PATH), ubah hanya yang Anda butuhkan. Dan mencoba untuk mengekspresikan mereka relatif CMAKE_BINARY_DIR, CMAKE_CURRENT_BINARY_DIR, PROJECT_BINARY_DIRdsb

Jika Anda melihat dokumentasi CMake, Anda akan melihat variabel dipartisi menjadi beberapa bagian semantik. Kecuali untuk keadaan yang sangat khusus, Anda harus memperlakukan semua yang terdaftar di bawah "Variabel yang Memberikan Informasi" sebagai hanya-baca di dalam CMakeLists.

Angew tidak lagi bangga dengan SO
sumber
2
Saya mulai menggunakan cmake dengan build di direktori src ... teknik ini awalnya gagal. Setelah saya menghapus semua file / cache cmake build di direktori src, teknik ini berfungsi. Terima kasih!
Avi Tevet
18
Mungkin lebih baik tidak menyarankan penggunaan rm -rf *. Tidak cantik jika cd Compilegagal ...
Roman
2
@ Roman Saya menganggap contoh baris perintah seperti itu cukup banyak pseudo-code. Ini kurang bertele-tele dan lebih tepat daripada mengetik "masukkan direktori Compile, hapus semua yang ada di sana, lalu jalankan CMake dengan jalur ke direktori sumber". Saya mengasumsikan akal sehat & penilaian dasar dari sebagian pembaca.
Angew tidak lagi bangga dengan SO
@ AviTevet: Saya pikir ini adalah jawaban yang benar. Jika ada file cache cmake dari pemanggilan cmake sebelumnya di dalam direktori sumber, Anda tidak akan mendapatkan cmake untuk memilih direktori lain untuk file yang dibuat, kecuali jika Anda menghapus semua yang lama dari direktori sumber. Perilaku yang cukup rusak oleh CMake menurut saya. Mengapa Anda tidak menulis jawaban lain?
Jo Jadi
113

Kedengarannya seperti Anda menginginkan build out of source . Ada beberapa cara untuk membuat build di luar sumber.

  1. Lakukan apa yang kamu lakukan, lari

    cd /path/to/my/build/folder
    cmake /path/to/my/source/folder

    yang akan menyebabkan cmake untuk menghasilkan pohon membangun di /path/to/my/build/folderatas pohon sumber di /path/to/my/source/folder.

    Setelah Anda membuatnya, cmake mengingat di mana folder sumber berada - sehingga Anda dapat menjalankan kembali cmake di pohon build dengan

    cmake /path/to/my/build/folder

    atau bahkan

    cmake .

    jika direktori Anda saat ini sudah menjadi folder build.

  2. Untuk CMake 3.13 atau yang lebih baru, gunakan opsi ini untuk mengatur sumber dan folder build

    cmake -B/path/to/my/build/folder -S/path/to/my/source/folder
  3. Untuk CMake yang lebih lama, gunakan beberapa opsi tidak berdokumen untuk menyetel folder sumber dan build :

    cmake -B/path/to/my/build/folder -H/path/to/my/source/folder

    yang akan melakukan hal yang persis sama seperti (1), tetapi tanpa bergantung pada direktori kerja saat ini.

CMake menempatkan semua outputnya di pohon build secara default, jadi kecuali Anda secara bebas menggunakan ${CMAKE_SOURCE_DIR}atau ${CMAKE_CURRENT_SOURCE_DIR}dalam file cmake Anda, itu tidak boleh menyentuh pohon sumber Anda .

Hal terbesar yang bisa salah adalah jika sebelumnya Anda telah membuat pohon build di pohon sumber Anda (misalnya, Anda memiliki build dalam sumber ). Setelah Anda melakukan ini, bagian kedua dari (1) di atas dimulai, dan cmake tidak membuat perubahan apa pun pada sumber atau lokasi pembuatan. Jadi, Anda tidak dapat membuat build out-of-source untuk direktori sumber dengan build dalam-sumber . Anda dapat memperbaikinya dengan cukup mudah dengan menghapus (minimal) CMakeCache.txtdari direktori sumber. Ada beberapa file lain (kebanyakan di CMakeFilesdirektori) yang dihasilkan CMake yang harus Anda hapus juga, tetapi ini tidak akan menyebabkan cmake memperlakukan pohon sumber sebagai pohon build.

Karena build out-of-source seringkali lebih diinginkan daripada build dalam-sumber, Anda mungkin ingin memodifikasi cmake Anda agar memerlukan build di luar sumber:

# Ensures that we do an out of source build

MACRO(MACRO_ENSURE_OUT_OF_SOURCE_BUILD MSG)
     STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}"
     "${CMAKE_BINARY_DIR}" insource)
     GET_FILENAME_COMPONENT(PARENTDIR ${CMAKE_SOURCE_DIR} PATH)
     STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}"
     "${PARENTDIR}" insourcesubdir)
    IF(insource OR insourcesubdir)
        MESSAGE(FATAL_ERROR "${MSG}")
    ENDIF(insource OR insourcesubdir)
ENDMACRO(MACRO_ENSURE_OUT_OF_SOURCE_BUILD)

MACRO_ENSURE_OUT_OF_SOURCE_BUILD(
    "${CMAKE_PROJECT_NAME} requires an out of source build."
)

Makro di atas berasal dari modul yang biasa digunakan bernama MacroOutOfSourceBuild. Ada banyak sumber tentang MacroOutOfSourceBuild.cmakedi google tetapi saya tidak dapat menemukan yang asli dan itu cukup pendek untuk dimasukkan di sini secara lengkap.

Sayangnya cmake biasanya telah menulis beberapa file pada saat makro dipanggil, jadi meskipun itu akan menghentikan Anda untuk benar-benar melakukan pembangunan, Anda masih perlu menghapus CMakeCache.txtdan CMakeFiles.

Anda mungkin merasa berguna untuk menyetel jalur tempat penulisan biner, pustaka bersama, dan pustaka statis - dalam hal ini lihat bagaimana cara membuat keluaran cmake menjadi dir 'bin'? (penafian, saya memiliki jawaban dengan suara terbanyak untuk pertanyaan itu ... tapi begitulah cara saya mengetahuinya).

Adam Bowen
sumber
Sebenarnya opsi untuk mengatur folder sumber adalah -S, bukan-H
smac89
@ smac89 Terima kasih! Sepertinya mereka mendokumentasikannya di 3.13 - Saya telah memperbarui jawaban untuk mencerminkan CMake modern.
Adam Bowen
8

Mengubah komentar saya menjadi jawaban:

Jika ada yang melakukan apa yang saya lakukan, yang dimulai dengan meletakkan semua file build di direktori sumber:

cd src
cmake .

cmake akan menempatkan sekelompok file membangun dan file cache ( CMakeCache.txt, CMakeFiles, cmake_install.cmake, dll) di srcdir.

Untuk mengubah ke build di luar sumber, saya harus menghapus semua file itu. Kemudian saya bisa melakukan apa yang direkomendasikan @Angew dalam jawabannya:

mkdir -p src/build
cd src/build
cmake ..
Avi Tevet
sumber
7

Pada CMake Wiki :

CMAKE_BINARY_DIR jika Anda membuat dalam sumber, ini sama dengan CMAKE_SOURCE_DIR, jika tidak, ini adalah direktori level teratas dari pohon build Anda

Bandingkan kedua variabel ini untuk menentukan apakah build out-of-source telah dimulai

sialan
sumber
6

Anda tidak boleh bergantung pada nama direktori build yang di-hardcode dalam skrip Anda, jadi baris dengan ../Compileharus diubah.

Itu karena harus terserah pengguna mana yang akan dikompilasi.

Alih-alih menggunakan salah satu variabel standar: http://www.cmake.org/Wiki/CMake_Useful_Variables (cari CMAKE_BINARY_DIRdan CMAKE_CURRENT_BINARY_DIR)

Michał Walenciak
sumber
2
sebenarnya inilah yang saya cari - CMAKE_CURRENT_BINARY_DIR , biasanya akan memberi tahu tentang jalur build biner saat ini. Mungkin bisa digunakan untuk menyetel dependen libs / bin build.
parasrish