แพคเกจสนิมที่มีทั้งไลบรารีและไบนารีหรือไม่


190

ฉันต้องการสร้างแพคเกจ Rust ที่มีทั้งไลบรารีที่สามารถใช้ซ้ำได้

สมมติว่าฉันไม่ได้สับสนความหมายใด ๆ ในระบบโมดูลสนิมCargo.tomlไฟล์ของฉันควรมีลักษณะอย่างไร

คำตอบ:


205
Tok:tmp doug$ du -a

8   ./Cargo.toml
8   ./src/bin.rs
8   ./src/lib.rs
16  ./src

Cargo.toml:

[package]
name = "mything"
version = "0.0.1"
authors = ["me <me@gmail.com>"]

[lib]
name = "mylib"
path = "src/lib.rs"

[[bin]]
name = "mybin"
path = "src/bin.rs"

src / lib.rs:

pub fn test() {
    println!("Test");
}

src / bin.rs:

extern crate mylib; // not needed since Rust edition 2018

use mylib::test;

pub fn main() {
    test();
}

2
ขอบคุณดั๊กฉันจะลอง! คำอธิบายประกอบ #! [crate_name =] และ #! [crate_type] เป็นตัวเลือกหรือไม่
Andrew Wagner

4
เมื่อคุณใช้คาร์โก้ตัวเลือกเหล่านี้ไม่จำเป็นเนื่องจากคาร์โก้ส่งต่อเป็นธงคอมไพเลอร์ หากคุณเรียกใช้cargo build --verboseคุณจะเห็นพวกเขาในrustcบรรทัดคำสั่ง
Vladimir Matveev

33
คุณรู้หรือไม่ว่าเหตุใด[[bin]]อาร์เรย์จึงเป็นตาราง ทำไมต้องใช้[[bin]]และไม่ได้[bin]? ดูเหมือนจะไม่มีเอกสารใด ๆ เกี่ยวกับเรื่องนี้
CMCDragonkai

40
@CMCDragonkai เป็นสเป็ครูปแบบ Toml [[x]] เป็นอาร์เรย์ที่มีการยกเลิกการ deserialized กล่าวคือ ลังเดี่ยวอาจสร้างหลายไบนารี แต่มีเพียงหนึ่งไลบรารี (เช่น [lib] ไม่ใช่ [[lib]]) คุณสามารถมีหลายช่องส่วน (ฉันเห็นด้วยมันดูแปลก ๆ แต่ Toml เป็นตัวเลือกที่ถกเถียงกันอยู่เสมอ)
Doug

1
มีวิธีการป้องกันไม่ให้รวบรวมไบนารีเมื่อทั้งหมดที่ฉันต้องการคือ lib หรือไม่ ไบนารีมีการพึ่งพาเพิ่มเติมซึ่งฉันเพิ่มผ่านคุณสมบัติที่เรียกว่า "ไบนารี" เมื่อฉันพยายามรวบรวมโดยไม่มีคุณสมบัตินั้นมันล้มเหลวในการสร้าง มันบ่นว่าไม่สามารถหาลังที่ bin.rs กำลังพยายามนำเข้า
บุคคล 93

150

นอกจากนี้คุณยังสามารถเพียงแค่ใส่แหล่งไบนารีในและส่วนที่เหลือของแหล่งที่มาของคุณในsrc/bin srcคุณสามารถดูตัวอย่างในโครงการของฉัน คุณไม่จำเป็นต้องแก้ไขไฟล์ของคุณCargo.tomlเลยและไฟล์ต้นฉบับแต่ละไฟล์จะถูกรวบรวมเป็นไบนารี่ที่มีชื่อเดียวกัน

การกำหนดค่าของคำตอบอื่น ๆ จะถูกแทนที่ด้วย:

$ tree
.
├── Cargo.toml
└── src
    ├── bin
    │   └── mybin.rs
    └── lib.rs

Cargo.toml

[package]
name = "example"
version = "0.0.1"
authors = ["An Devloper <an.devloper@example.com>"]

src / lib.rs

use std::error::Error;

pub fn really_complicated_code(a: u8, b: u8) -> Result<u8, Box<Error>> {
    Ok(a + b)
}

src / bin / mybin.rs

extern crate example; // Optional in Rust 2018

fn main() {
    println!("I'm using the library: {:?}", example::really_complicated_code(1, 2));
}

และดำเนินการ:

$ cargo run --bin mybin
I'm using the library: Ok(3)

นอกจากนี้คุณสามารถสร้างsrc/main.rsที่จะใช้เป็นปฏิบัติการ defacto น่าเสียดายที่สิ่งนี้ขัดแย้งกับcargo docคำสั่ง:

ไม่สามารถจัดทำเอกสารแพคเกจที่ห้องสมุดและไบนารีมีชื่อเดียวกัน พิจารณาเปลี่ยนชื่อหนึ่งหรือทำเครื่องหมายเป้าหมายเป็นdoc = false


13
เข้ากันได้ดีกับวิธีการกำหนดค่าแบบแผนของการเกิดสนิม! ทั้งคำตอบด้วยกันและคุณมีความสะดวกสบายและความยืดหยุ่น
แกะบิน

9
extern crate example;ไม่จำเป็นต้องใช้เป็นสนิม 2018 คุณสามารถเขียนuse example::really_complicated_code;และใช้งานฟังก์ชั่นได้โดยตรงโดยไม่ต้องตั้งชื่อขอบเขต
sassman

47

ทางเลือกอื่นคือไม่พยายามยัดทั้งสองอย่างไว้ในแพ็คเกจเดียว สำหรับโครงการขนาดใหญ่ขึ้นเล็กน้อยที่มีการปฏิบัติการที่เป็นมิตรฉันพบว่ามันดีมากที่จะใช้พื้นที่ทำงาน

เราสร้างโปรเจ็กต์ไบนารีที่มีไลบรารี่อยู่ภายใน:

the-binary
├── Cargo.lock
├── Cargo.toml
├── mylibrary
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
└── src
    └── main.rs

Cargo.toml

สิ่งนี้ใช้[workspace]คีย์และขึ้นอยู่กับไลบรารี:

[package]
name = "the-binary"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]

[workspace]

[dependencies]
mylibrary = { path = "mylibrary" }

src / main.rs

extern crate mylibrary;

fn main() {
    println!("I'm using the library: {:?}", mylibrary::really_complicated_code(1, 2));
}

MyLibrary / src / lib.rs

use std::error::Error;

pub fn really_complicated_code(a: u8, b: u8) -> Result<u8, Box<Error>> {
    Ok(a + b)
}

และดำเนินการ:

$ cargo run
   Compiling mylibrary v0.1.0 (file:///private/tmp/the-binary/mylibrary)
   Compiling the-binary v0.1.0 (file:///private/tmp/the-binary)
    Finished dev [unoptimized + debuginfo] target(s) in 0.73 secs
     Running `target/debug/the-binary`
I'm using the library: Ok(3)

มีประโยชน์ใหญ่สองประการสำหรับโครงการนี้:

  1. ตอนนี้ไบนารีสามารถใช้การอ้างอิงที่ใช้กับมันเท่านั้น ตัวอย่างเช่นคุณสามารถรวมลังจำนวนมากเพื่อปรับปรุงประสบการณ์ผู้ใช้เช่นตัวแยกวิเคราะห์บรรทัดคำสั่งหรือการจัดรูปแบบเทอร์มินัล สิ่งเหล่านี้จะ "ไม่ติด" ในห้องสมุด

  2. พื้นที่ทำงานป้องกันการสร้างซ้ำซ้อนของแต่ละองค์ประกอบ หากเราทำงานcargo buildทั้งในmylibraryและthe-binaryไดเรกทอรีห้องสมุดจะไม่ถูกสร้างขึ้นทั้งสองครั้ง - มันถูกใช้ร่วมกันระหว่างทั้งสองโครงการ


ดูเหมือนว่าจะเป็นวิธีที่ดีกว่ามาก เห็นได้ชัดว่าเป็นเวลาหลายปีแล้วที่มีคนถามคำถามนี้ แต่ผู้คนยังคงดิ้นรนกับการจัดโครงการขนาดใหญ่ มีข้อเสียคือการใช้พื้นที่ทำงานเมื่อเทียบกับคำตอบที่เลือกข้างต้น?
Jspies

4
@Jspies ข้อเสียที่ยิ่งใหญ่ที่สุดที่ฉันสามารถคิดได้จากส่วนบนของหัวของฉันคือมีเครื่องมือบางอย่างที่ไม่รู้วิธีจัดการกับพื้นที่ทำงาน พวกเขาอยู่ในจุดที่แปลกเมื่อโต้ตอบกับเครื่องมือที่มีอยู่ที่มีแนวคิด "โครงการ" บางประเภท โดยส่วนตัวแล้วฉันมักจะใช้วิธีการต่อเนื่อง: ฉันเริ่มต้นด้วยทุกสิ่งในmain.rsนั้นแล้วแบ่งมันเป็นโมดูลเมื่อมันใหญ่ขึ้นในที่สุดก็แยกออกไปsrc/binเมื่อมันใหญ่ขึ้นเล็กน้อยจากนั้นย้ายไปยังพื้นที่ทำงานเมื่อฉันเริ่มใช้ตรรกะหลักอย่างหนัก
Shepmaster

ขอบคุณฉันจะให้มันหมุน โครงการปัจจุบันของฉันมี libs สองสามตัวที่พัฒนาขึ้นเพื่อเป็นส่วนหนึ่งของโครงการ แต่ก็ใช้ภายนอกเช่นกัน
Jspies

มันสร้างและทำงานได้ดี แต่cargo testดูเหมือนว่าจะไม่สนใจการทดสอบหน่วยใน lib.rs
Stein

3
@ Stein ฉันคิดว่าคุณต้องการcargo test --all
Shepmaster

18

คุณสามารถใส่lib.rsและmain.rsไปยังโฟลเดอร์แหล่งที่มาด้วยกัน ไม่มีความขัดแย้งและสินค้าจะสร้างทั้งสองอย่าง

หากต้องการแก้ไขความขัดแย้งของเอกสารให้เพิ่มในCargo.toml:

[[bin]]
name = "main"
doc = false

3
ที่จะครอบคลุมโดย " นอกจากนี้คุณเพียงแค่สร้าง src / main.rs ที่จะใช้เป็นปฏิบัติการ defacto " ในคำตอบอื่น ๆ ไม่? และความขัดแย้งของเอกสารจะได้รับการแก้ไขโดยคำตอบที่ยอมรับใช่ไหม? คุณอาจต้องชี้แจงคำตอบของคุณให้ชัดเจนเพื่อแสดงว่าเหตุใดจึงไม่เหมือนกัน มันก็โอเคที่จะอ้างอิงคำตอบอื่น ๆ เพื่อสร้างพวกเขา
Shepmaster
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.