Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Cargo Çalışma Alanları

  1. bölümde hem ikili crate hem de kütüphane crate içeren bir paket oluşturmuştuk. Projeniz büyüdükçe kütüphane crate’in de büyümeye devam ettiğini ve paketi birden fazla kütüphane crate’e bölmek istediğinizi fark edebilirsiniz. Cargo’nun çalışma alanı (workspace) adı verilen özelliği, birlikte geliştirilen ilişkili birden çok paketi yönetmeyi kolaylaştırır.

Bir Çalışma Alanı Oluşturmak

Çalışma alanı, aynı Cargo.lock dosyasını ve aynı çıktı dizinini paylaşan paketler kümesidir. Yapıya odaklanabilmek için basit kod kullanan bir çalışma alanı örneği oluşturalım. Çalışma alanını düzenlemenin farklı yolları vardır; biz yalnızca yaygın bir yaklaşımı göstereceğiz. Bir ikili crate ve iki kütüphane crate içeren bir çalışma alanımız olacak. Ana işlevi sunacak ikili crate, iki kütüphaneye bağımlı olacak. Kütüphanelerden biri bir_ekle fonksiyonunu, diğeri ise iki_ekle fonksiyonunu sağlayacak. Bu üç crate aynı çalışma alanının parçası olacak. Önce çalışma alanı için yeni bir dizin oluşturalım:

$ mkdir add
$ cd add

Ardından add dizininde, tüm çalışma alanını yapılandıracak Cargo.toml dosyasını oluşturalım. Bu dosyada [package] bölümü olmayacak. Onun yerine üyeleri eklememizi sağlayacak bir [workspace] bölümüyle başlayacak. Ayrıca çözümleyicinin en güncel sürümünü kullanmak için resolver değerini "3" yapacağız:

Dosya Adı: Cargo.toml

[workspace]
resolver = "3"

Şimdi topla dizini içinde cargo new çalıştırarak toplayici ikili crate’ini oluşturalım:

$ cargo new toplayici
     Created binary (application) `toplayici` package
      Adding `toplayici` as member of workspace at `file:///projects/topla`

Bir çalışma alanı içinde cargo new çalıştırıldığında, Cargo yeni oluşturulan paketi çalışma alanı Cargo.toml dosyasındaki [workspace] tanımının members anahtarına da otomatik olarak ekler:

[workspace]
resolver = "3"
members = ["toplayici"]

Bu noktada cargo build çalıştırarak çalışma alanını derleyebiliriz. topla dizininizin dosya yapısı şu hale gelir:

├── Cargo.lock
├── Cargo.toml
├── toplayici
│   ├── Cargo.toml
│   └── src
│       └── main.rs
└── target

Çalışma alanının en üst düzeyde tek bir target dizini vardır ve derlenmiş yapıtlar bu dizine yazılır; toplayici paketinin kendine ait bir target dizini yoktur. Hatta cargo buildi toplayici dizininden çalıştırsak bile çıktılar yine topla/target altına gider; topla/toplayici/target altına değil. Cargo çalışma alanlarında target dizinini böyle düzenler çünkü bu crate’lerin birbirine bağımlı olması beklenir. Her crate’in kendi target dizini olsaydı, her crate diğer crate’leri de kendi dizinine çıktı koymak için yeniden derlemek zorunda kalırdı. Ortak bir target dizini paylaşmak gereksiz yeniden derlemeleri önler.

Çalışma Alanına İkinci Paketi Eklemek

Şimdi çalışma alanına bir üye paket daha ekleyelim ve buna bir_ekle diyelim. bir_ekle adlı yeni bir kütüphane crate’i üretin:

$ cargo new bir_ekle --lib
     Created library `bir_ekle` package
      Adding `bir_ekle` as member of workspace at `file:///projects/topla`

Üst düzey Cargo.toml artık members listesinde bir_ekle yolunu da içerir:

Dosya Adı: Cargo.toml

[workspace]
resolver = "3"
members = ["toplayici", "bir_ekle"]

topla dizininizin dosya yapısı artık şöyle olur:

├── Cargo.lock
├── Cargo.toml
├── bir_ekle
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
├── toplayici
│   ├── Cargo.toml
│   └── src
│       └── main.rs
└── target

Şimdi bir_ekle/src/lib.rs dosyasına bir_ekle fonksiyonunu ekleyelim:

Dosya Adı: bir_ekle/src/lib.rs

pub fn bir_ekle(x: i32) -> i32 {
    x + 1
}

Artık ikili crate’imizi barındıran toplayici paketinin, bu kütüphaneyi içeren pakete bağımlı olmasını sağlayabiliriz. Önce toplayici/Cargo.toml dosyasına bu crate için yol bağımlılığı eklememiz gerekir.

Dosya Adı: toplayici/Cargo.toml

[dependencies]
bir_ekle = { path = "../bir_ekle", package = "bir_ekle" }

Cargo, çalışma alanındaki crate’lerin birbirine bağımlı olacağını kendiliğinden varsaymaz; bu ilişkileri açıkça yazmamız gerekir.

Şimdi toplayici crate’inde bir_ekle fonksiyonunu kullanalım. toplayici/src/main.rs dosyasını açıp main fonksiyonunu, Liste 14-7’deki gibi bir_ekle fonksiyonunu çağıracak şekilde değiştirin.

Filename: toplayici/src/main.rs
fn main() {
    let sayi = 10;
    println!(
        "Merhaba, dünya! {sayi} artı bir {} eder!",
        bir_ekle::bir_ekle(sayi)
    );
}
Listing 14-7: toplayici crate’inden bir_ekle kutuphane fonksiyonunu kullanmak

Şimdi çalışma alanının en üst düzeyindeki topla dizininde cargo build çalıştırarak her şeyi derleyelim!

$ cargo build
   Compiling bir_ekle v0.1.0 (file:///projects/topla/bir_ekle)
   Compiling toplayici v0.1.0 (file:///projects/topla/toplayici)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.22s

İkili crate’i topla dizininden çalıştırmak için, çalışma alanındaki hangi paketi çalıştırmak istediğimizi -p bayrağı ve paket adıyla belirtiriz:

$ cargo run -p toplayici
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/toplayici`
Merhaba, dünya! 10 artı bir 11 eder!

Bu komut, toplayici/src/main.rs içindeki ve bir_ekle crate’ine bağımlı olan kodu çalıştırır.

Harici Bir Pakete Bağımlı Olmak

Çalışma alanında her crate dizininde ayrı bir Cargo.lock yerine, üst düzeyde tek bir Cargo.lock dosyası bulunduğuna dikkat edin. Bu, tüm crate’lerin tüm bağımlılıkların aynı sürümünü kullanmasını sağlar. toplayici/Cargo.toml ve bir_ekle/Cargo.toml dosyalarına rand paketini eklersek, Cargo bunları tek bir rand sürümüne çözer ve bunu tek Cargo.lock dosyasına yazar. Böylece çalışma alanındaki tüm crate’ler birbirleriyle uyumlu kalır. Şimdi rand crate’ini bir_ekle/Cargo.toml içindeki [dependencies] bölümüne ekleyelim ki onu bir_ekle crate’inde kullanabilelim:

Dosya Adı: bir_ekle/Cargo.toml

[dependencies]
rand = "0.8.5"

Şimdi bir_ekle/src/lib.rs dosyasına use rand; ekleyebiliriz. Ardından topla dizininde cargo build çalıştırınca, tüm çalışma alanıyla birlikte rand crate’i de indirilip derlenir. randı kapsama aldığımız halde kullanmadığımız için bir uyarı görürüz:

$ cargo build
    Updating crates.io index
  Downloaded rand v0.8.5
   --snip--
   Compiling rand v0.8.5
   Compiling bir_ekle v0.1.0 (file:///projects/topla/bir_ekle)
warning: unused import: `rand`
 --> bir_ekle/src/lib.rs:1:5
  |
1 | use rand;
  |     ^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: `bir_ekle` (lib) generated 1 warning (run `cargo fix --lib -p bir_ekle` to apply 1 suggestion)
   Compiling toplayici v0.1.0 (file:///projects/topla/toplayici)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.95s

Artık üst düzey Cargo.lock dosyası, bir_ekle crate’inin rand bağımlılığına ilişkin bilgiyi içerir. Ama rand çalışma alanında bir yerde kullanılıyor diye, onu diğer crate’lerde de otomatik kullanamayız; bunun için onların Cargo.toml dosyalarına da rand eklememiz gerekir. Örneğin toplayici paketine ait toplayici/src/main.rs dosyasına use rand; yazarsak hata alırız:

$ cargo build
  --snip--
   Compiling toplayici v0.1.0 (file:///projects/topla/toplayici)
error[E0432]: unresolved import `rand`
 --> toplayici/src/main.rs:2:5
  |
2 | use rand;
  |     ^^^^ no external crate `rand`

Bunu düzeltmek için toplayici paketinin Cargo.toml dosyasını düzenleyip randın ona da bağımlılık olduğunu belirtmemiz gerekir. toplayici paketini derlemek, Cargo.lock içinde toplayici için bağımlılık listesine randı ekler; ama randın ek bir kopyası indirilmez. Cargo, çalışma alanındaki her pakette rand kullanan crate’lerin, uyumlu sürüm belirttikleri sürece aynı rand sürümünü kullanmasını sağlar. Bu da hem yer kazandırır hem de crate’lerin birbiriyle uyumlu kalmasını sağlar.

Çalışma alanındaki crate’ler aynı bağımlılığın birbiriyle uyumsuz sürümlerini isterse, Cargo hepsini ayrı ayrı çözer; ama yine de olabildiğince az sayıda sürüm kullanmaya çalışır.

Çalışma Alanına Test Eklemek

Bir geliştirme daha yapalım ve bir_ekle crate’i içinde bir_ekle::bir_ekle fonksiyonu için bir test ekleyelim:

Dosya Adı: bir_ekle/src/lib.rs

pub fn bir_ekle(x: i32) -> i32 {
    x + 1
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn calisir() {
        assert_eq!(3, bir_ekle(2));
    }
}

Şimdi üst düzey topla dizininde cargo test çalıştırın. Böyle yapılandırılmış bir çalışma alanında cargo test, çalışma alanındaki tüm crate’lerin testlerini çalıştırır:

$ cargo test
   Compiling bir_ekle v0.1.0 (file:///projects/topla/bir_ekle)
   Compiling toplayici v0.1.0 (file:///projects/topla/toplayici)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.20s
     Running unittests src/lib.rs (target/debug/deps/bir_ekle-93c49ee75dc46543)

running 1 test
test tests::calisir ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running unittests src/main.rs (target/debug/deps/toplayici-3a47283c568d2b6a)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests bir_ekle

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Çıktının ilk bölümü, bir_ekle crate’i içindeki calisir testinin geçtiğini gösterir. Sonraki bölümde toplayici crate’inde hiç test bulunmadığını, son bölümde de bir_ekle crate’inde hiç belge testi olmadığını görürüz.

Üst düzey dizinden, çalışma alanındaki tek bir crate için de test çalıştırabiliriz. Bunun için -p bayrağını kullanıp test etmek istediğimiz crate adını belirtiriz:

$ cargo test -p bir_ekle
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.00s
     Running unittests src/lib.rs (target/debug/deps/bir_ekle-93c49ee75dc46543)

running 1 test
test tests::calisir ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests bir_ekle

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Bu çıktı, cargo testin yalnızca bir_ekle crate’inin testlerini çalıştırdığını ve toplayici crate’inin testlerini çalıştırmadığını gösterir.

Çalışma alanındaki crate’leri crates.io üzerinde yayımlarsanız, her crate’i ayrı ayrı yayımlamanız gerekir. cargo test örneğinde olduğu gibi, -p bayrağını kullanarak çalışma alanındaki belirli bir crate’i yayımlayabilirsiniz.

Ek pratik olarak, bu çalışma alanına iki_ekle adında bir crate’i de bir_ekle crate’iyle benzer biçimde ekleyin!

Projeniz büyüdükçe çalışma alanı kullanmayı düşünün: Tek parça büyük bir kod yığını yerine daha küçük ve daha kolay anlaşılır bileşenlerle çalışmanıza olanak tanır. Üstelik çalışma alanındaki crate’ler aynı anda sık değişiyorsa, aralarındaki eşgüdümü de kolaylaştırır.