Untuk membina fail boleh laksana Mac natif daripada beberapa fail C++, hantarkan setiap fail pelaksanaan yang diperlukan kepada clang++, atau susunkannya menjadi fail objek dan pautkan semuanya. Panduan ini membina program Terminal kecil dan menerangkan cara mendiagnosis definisi yang hilang.

Sediakan alat penyusun Mac

Gunakan aliran kerja ini untuk program C++ kecil yang ingin anda jalankan secara setempat dalam Terminal. Apple menyediakan penyusun dan SDK macOS melalui Xcode atau pakej Command Line Tools kendiri. Jika Xcode sudah dipasang, anda tidak memerlukan pakej berasingan itu. Jika tidak, jalankan arahan berikut dan lengkapkan dialog pemasangan. Lihat Memasang alat baris perintah.

xcode-select --install

Selepas pemasangan, semak sama ada penyusun tersedia:

clang++ --version

Gunakan clang++ untuk pemautan akhir, termasuk apabila input anda sudah berupa fail objek yang telah disusun. Dokumentasi Clang secara jelas mengesyorkan pemacu ini untuk program C++ kerana mod bahasa menentukan pustaka masa jalan yang dipautkan secara automatik. Lihat Menyusun Rantaian Alat Lengkap.

Bina program C++ lengkap yang terdiri daripada tiga fail

Contoh rekaan ini mengira item pada tiga dulang meja dan memformatkan hasilnya. Ia mempunyai satu titik masuk dan dua fail pelaksanaan sokongan. Cipta direktori kerja baharu yang kosong, kemudian simpan empat fail ini terus di dalamnya:

desk-demo/
  desk.hpp
  main.cpp
  label.cpp
  totals.cpp

Simpan pengisytiharan kongsi sebagai desk.hpp:

#ifndef DESK_DEMO_DESK_HPP
#define DESK_DEMO_DESK_HPP

#include <string>

std::string make_label(int count);
int total_items(int trays, int per_tray);

#endif

Simpan titik masuk sebagai main.cpp:

#include "desk.hpp"
#include <iostream>

int main() {
    const int count = total_items(3, 4);
    std::cout << make_label(count) << '\n';
    return 0;
}

Simpan pelaksanaan pemformatan sebagai label.cpp:

#include "desk.hpp"

std::string make_label(int count) {
    return "Desk items: " + std::to_string(count);
}

Simpan pelaksanaan pengiraan sebagai totals.cpp:

#include "desk.hpp"

int total_items(int trays, int per_tray) {
    return trays * per_tray;
}

Setiap pelaksanaan menyertakan pengepala yang sama, membolehkan penyusun menyemak definisi fungsinya berdasarkan pengisytiharan kongsi. Pengawal pengepala menghalang penyertaan berulang dalam satu unit terjemahan. Kekalkan badan fungsi biasa bukan sebaris ini dalam fail pelaksanaannya; C++ menetapkan keperluan definisi merentas program melalui peraturan satu definisi.

Susun dan pautkan dengan satu arahan

Buka Terminal dalam direktori yang mengandungi empat fail tersebut dan jalankan:

clang++ -std=c++17 main.cpp label.cpp totals.cpp -o desk-demo && ./desk-demo

Output yang dijangka ialah:

Desk items: 12

Arahan ini menyenaraikan ketiga-tiga fail pelaksanaan dan menetapkan nama output dengan -o. Oleh sebab tiada pilihan untuk menghentikan peringkat seterusnya, Clang menyusun input dan memanggil pemaut. -std=c++17 yang dinyatakan secara jelas memilih versi bahasa dan bukannya bergantung pada tetapan lalai penyusun. Pilihan ini didokumenkan dalam Panduan arahan penyusun Clang.

Shell hanya menjalankan fail boleh laksana jika binaan berjaya kerana arahan disambungkan dengan &&. Ini penting apabila membina semula: binaan yang gagal tidak sepatutnya diikuti dengan menjalankan fail boleh laksana lama secara tidak sengaja lalu menyangka outputnya ialah hasil baharu.

Bilakah kad bebas sesuai digunakan?

Untuk direktori khusus ini, arahan berikut boleh menggantikan senarai sumber yang dinyatakan secara jelas:

clang++ -std=c++17 ./*.cpp -o desk-demo && ./desk-demo

Shell mengembangkan ./*.cpp kepada fail yang sepadan dalam direktori semasa. Ia tidak mencari dalam folder bersarang atau menyertakan fail berakhiran .cc atau .cxx. Petik laluan individu yang mengandungi ruang apabila anda menamakannya secara jelas.

Gunakan kad bebas hanya selagi setiap fail yang sepadan tergolong dalam fail boleh laksana ini. Jika kemudian anda menambah program demonstrasi berasingan yang mempunyai main sendiri, atau pelaksanaan alternatif khusus platform, kekalkan senarai sumber yang dinyatakan secara jelas. Dalam konteks ini, “semua fail pelaksanaan” bermaksud semua fail yang diperlukan oleh satu sasaran, dengan setiap definisi yang diperlukan dibekalkan dengan sewajarnya.

Susun fail objek dahulu, kemudian pautkannya

Mengasingkan peringkat memudahkan anda mengenal pasti sama ada kegagalan berlaku semasa penyusunan satu fail sumber atau semasa penggabungan program. Dengan menggunakan empat fail dan direktori kerja yang sama, jalankan:

(
    set -e
    mkdir -p build
    clang++ -std=c++17 -c main.cpp -o build/main.o
    clang++ -std=c++17 -c label.cpp -o build/label.o
    clang++ -std=c++17 -c totals.cpp -o build/totals.o
    clang++ build/main.o build/label.o build/totals.o -o build/desk-demo
    ./build/desk-demo
)

Pilihan -c menghasilkan fail objek tanpa pemautan. Panggilan penyusun terakhir menerima ketiga-tiga objek lalu memautkan fail boleh laksana. Ini mengikut peringkat penyusunan yang didokumenkan Clang. set -e dalam subshell menghentikan urutan arahan terus ini jika sesuatu arahan gagal.

Gunakan nama objek yang dinyatakan secara jelas di sini juga. Memautkan setiap objek dalam direktori binaan yang digunakan semula boleh memasukkan fail lama daripada versi terdahulu program secara tidak sengaja. Apabila dua fail sumber dalam folder berbeza berkongsi nama asas, berikan laluan berbeza kepada objeknya dan bukannya menulis kedua-duanya ke nama fail output yang sama.

Jika anda hanya mengubah label.cpp, anda boleh menyusun semula objek itu dan mengulangi arahan pemautan. Jika anda mengubah desk.hpp, bina semula setiap sumber yang menyertakannya. Aliran kerja manual ini memerlukan anda menjejaki hubungan tersebut; apabila projek semakin besar, sistem binaan lebih praktikal.

Diagnosis kegagalan sebelum mengubah arahan binaan

Urutan berikut menerapkan peringkat penyusunan dan peraturan definisi C++ pada contoh ini. Teks diagnostik yang tepat berbeza mengikut rantaian alat yang dipasang.

Gejala Perkara pertama yang perlu diperiksa Langkah seterusnya yang sesuai
Pengepala dilaporkan hilang Ejaan include dan lokasi pengepala Pulihkan susun atur yang ditunjukkan atau tetapkan direktori carian pengepala yang betul.
make_label atau total_items tidak ditakrifkan semasa pemautan Sama ada pelaksanaannya menjadi input Tambahkan fail .cpp yang hilang atau objek tersusunnya pada pemautan.
Fungsi masih tidak ditakrifkan walaupun failnya disertakan Tandatangan pengisytiharan dan definisi Bandingkan ruang nama, jenis parameter dan pengubah; sertakan pengepala kongsi dalam pelaksanaan.
Simbol pendua muncul Input pelaksanaan yang berulang Buang objek berulang, fail .cpp yang disertakan atau definisi alternatif yang tidak disengajakan.
main tidak ditakrifkan atau diduplikasi Fail titik masuk Sertakan main.cpp yang dimaksudkan tepat sekali dan kecualikan titik masuk program lain.
Simbol pustaka C++ tidak ditakrifkan Pemacu pemautan akhir Gunakan clang++ supaya pustaka masa jalan C++ dibekalkan.

Contohnya, menyusun main.cpp sahaja boleh menerima panggilan tersebut kerana pengepala mengisytiharkan kedua-dua fungsi. Namun, pemautan akhir masih memerlukan definisinya. Menambah satu lagi penyertaan pengepala tidak membekalkan objek pelaksanaan yang hilang. Keperluan asas ini diterangkan dalam peraturan satu definisi C++.

Elakkan membaiki simbol yang hilang dengan menyertakan label.cpp di dalam main.cpp sambil menyusun label.cpp secara berasingan. Ini membekalkan definisi fungsi biasa yang sama melalui dua unit terjemahan. Pengepala kongsi dan input pelaksanaan berasingan sudah menyediakan struktur yang dimaksudkan.

Untuk memeriksa arahan alat tanpa melaksanakan binaan, gunakan pilihan -### yang didokumenkan Clang. Petikkannya supaya shell menghantarnya tanpa perubahan:

clang++ '-###' -std=c++17 main.cpp label.cpp totals.cpp -o desk-demo

Ini mendedahkan panggilan penyusun dan pemaut yang dipilih oleh pemacu, sekali gus membantu membezakan arahan yang anda maksudkan daripada arahan yang akan dijalankan oleh rantaian alat. Lihat Menyusun Rantaian Alat Lengkap.

Kekalkan keserasian seni bina, platform dan ABI

Menambah setiap fail sumber tidak dapat membaiki input binari yang tidak serasi. Untuk binaan setempat, mulakan dengan satu rantaian alat Apple yang dipasang dan bina semula sumber program bersama-sama. Apabila menambah pustaka prabina, semak platform dan seni bina yang disokong sebelum mengubah senarai sumber.

Untuk binaan universal pilihan, Apple mendokumenkan penyusunan dan pemautan secara berasingan bagi setiap seni bina, kemudian menggabungkan fail boleh laksana yang siap dengan lipo. Dengan rantaian alat dan SDK yang menyokong kedua-dua sasaran, contoh yang sama boleh dibina seperti berikut. Sasaran penggunaan macOS 11 di bawah hanyalah pilihan ilustrasi:

(
    set -e
    mkdir -p build
    clang++ -std=c++17 -target arm64-apple-macos11 \
        main.cpp label.cpp totals.cpp -o build/desk-arm64
    clang++ -std=c++17 -target x86_64-apple-macos11 \
        main.cpp label.cpp totals.cpp -o build/desk-x86_64
    lipo -create build/desk-arm64 build/desk-x86_64 \
        -output build/desk-universal
    lipo -archs build/desk-universal
)

Setiap kebergantungan yang dipautkan mesti menyediakan input yang serasi untuk binaan seni bina yang sepadan. Binari iOS tidak menjadi binari macOS hanya kerana kedua-duanya menggunakan arm64. Apple menerangkan hirisan seni bina, perbezaan platform dan pemeriksaan fail boleh laksana dalam Membina binari macOS universal.

Versi bahasa C++ juga berbeza daripada keserasian binari atau ABI. Memadankan -std=c++17 sahaja tidak membuktikan bahawa pustaka yang dibina secara berasingan mempunyai susun atur dan konfigurasi yang serasi. LLVM mendokumenkan bendera konfigurasi pustaka yang mempengaruhi ABI dan menyatakan bahawa pengguna tidak sepatutnya menetapkan sendiri bendera vendor tersebut. Untuk tugasan ini, mengekalkan konfigurasi pustaka biasa daripada rantaian alat ialah pilihan yang praktikal. Lihat Jaminan ABI libc++.

Gunakan senarai sumber yang sama dalam Xcode atau projek Swift campuran

Dalam sasaran Xcode sedia ada, pilih sasaran dan buka Build Phases. Semak Compile Sources untuk melihat fail pelaksanaan yang diperlukan oleh fail boleh laksana itu. Tambahkan kebergantungan pustaka tersuai melalui Link Binary with Libraries. Apple mendokumenkan tanggungjawab yang berasingan ini dalam Menyesuaikan fasa binaan sasaran.

Untuk contoh ini, senarai sumber perlu merangkumi main.cpp, label.cpp dan totals.cpp. Meletakkan pengepala dalam projek tidak menggantikan penyusunan fail pelaksanaan.

Jika aplikasi yang mengelilinginya menggunakan Swift, arahan C++ tulen di atas hanya merangkumi program C++. Laluan yang didokumenkan Swift memerlukan kebolehoperasian C++ diaktifkan untuk mendedahkan API merentas bahasa; hanya ciri bahasa yang disokong boleh merentasi sempadan tersebut. Lihat Menggabungkan Swift dan C++.

Kod Swift dan C++ campuran mesti menggunakan pustaka standard C++ yang sama; pada platform Apple, Swift menggunakan libc++. Swift turut mendokumenkan kekangan penyusun dan versi bahasa, termasuk C++14 atau lebih baharu untuk kebolehoperasian. Semak keperluan tersebut sebelum menganggap pustaka sedia ada sebagai kebergantungan yang serasi. Lihat Ciri dan Kekangan Kebolehoperasian C++ yang Disokong.

Untuk tugasan Terminal setempat, mulakan dengan binaan tiga sumber yang dinyatakan secara jelas. Jika gagal, kenal pasti peringkat yang gagal, semak definisi yang hilang atau berulang dan pastikan input binari serasi. Setelah arahan itu menghasilkan hasil yang dijangka, anda boleh membawa senarai sumber konkrit itu ke dalam binaan yang lebih besar.

Sumber