LINUX.ORG.RU

Rust и Makefile, как?

 


0

3
$ echo 'fn main() {}' > main.rs
$ rustc --emit=obj main.rs 
$ rustc main.o -o main
error: couldn't read main.o: stream did not contain valid UTF-8
error: aborting due to previous error
$ cc main.o
/usr/bin/ld: main.o: in function `std::rt::lang_start' ... undefined reference to `std::rt::lang_start_internal'

Есть ли способ узнать что мне именно нужно линковать сейчас?

★★★★★

Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от vbr

rustc вызывает на главный файл, потом rustc проходится по другим модулям и компилирует их. Может rust просто не умеет в раздельную компиляцию .rs?

MOPKOBKA ★★★★★
() автор топика
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

Я думаю, что раздельная компиляция реализована внутри rustc. Т.е. тебе надо вызвать его со списком rs файлов, а он уже сам разберётся, что надо пересобрать и перелинковать. Как ты хочешь, похоже, не получится.

vbr ★★★★
()
Последнее исправление: vbr (всего исправлений: 1)

Элементарно, ты пытаешься обратиться к use after free. После первого вызова rustc процесс завершается, и при следующем вызове имеем дело с deallocated memory. В с/с++ данный фокус проходил долгие годы через ЮБ, но к счастью в расте есть borrow checker. Данную vulnerability успешно использовали хакеры из Восточно-Западной Кореи (отчет ПАО «ВилкойВПенопластИлиХуемВРаст» за 2023 год).

Ну и это, как и в любой непонятной ситуации, стоит попробовать:

$ unsafe { rustc(main.o -o main).unwrap() }
kvpfs_2
()

В чем вопрос вообще, всеж работает

echo 'fn main() {}' > main.rs
rustc -o main main.rs
./main
Зачем отдельно линковать?

Если точка входа на другом языке написана и нужно слинковать в другой проект то собирай как статик либу и линкуй .a

echo '#[no_mangle] pub extern "C" fn hello() {}' > lib.rs
rustc --crate-type=staticlib -o hello.a lib.rs

pftBest ★★★★
()
Последнее исправление: pftBest (всего исправлений: 2)
Ответ на: комментарий от kvpfs_2

а как ты собираешься шарить мета информацию между этими калькуляторами, например информацию о типах и определения функций, не говоря уже о макросах. Так как в языке нету хедер файлов и их аналогов то компилятору придется загрузить в оперативу все .rs файлы в пределах текущего крейта и распарсить их. Если указать флаги на инкрементальную сборку то оно может прихранить мета инфу и второй раз все .rs файлы не парсить заново, но первая сборка все равно полная будет.

По калькуляторам размазать можно только на уровне крейтов, если ты зависимости имеешь больше одного то их можно паралельно собирать в .rlib и потом в верхнем крейте указать как зависимость в main.rs чтобы слинковались, но тут тоже не надо вручную линкер вызывать.

pftBest ★★★★
()
Ответ на: комментарий от pftBest

Я ненастоящий сварщик растаман, не могу сказать предметно по расту. Забавно, сколько раз слышал про убого-допотопный си со своими хидерами, а оно на деле вон как выходит …

kvpfs_2
()
Ответ на: комментарий от kvpfs_2

Забыл уточнить что один вызов rustc внутри использует паралельную компиляцию и во фронтенде и в llvm бекенде, поэтому в пределах одного калькулятора по ядрам раскидает сам без стронней помощи от мейкфайлов https://blog.rust-lang.org/2023/11/09/parallel-rustc.html.

Вообще да, хорошо сделаные хедер файлы позволяют раскинуть сборку по нескольким серверам а не только в пределах одного компа. Но с другой стороны если хедеры написаны абы как, и включают много ненужной информации, то это наооборот замедляет сильно сборку, даже если она параллельная.

Ну и писать хедеры нифига не удобно, в плюсах уже затащили модули, у них будет такая же проблема как и тут, что один модуль собираешь как один юнит и паралелится только в пределах одной системы.

pftBest ★★★★
()
Последнее исправление: pftBest (всего исправлений: 1)
Ответ на: комментарий от pftBest

в плюсах уже затащили модули, у них будет такая же проблема как и тут, что один модуль собираешь как один юнит и паралелится только в пределах одной системы.

Нет, это неправильное представление о плюсовых модулях, это модники-радикалы лишь считают, что всё будет теперь на них. Будут такие же сpp/hpp, и после некоторого порога это будет оборачиваться в модуль, порог вообще субъективен, может вся законченная либа.

Ну и писать хедеры нифига не удобно

Да, требует некоторых доп телодвижений, но и огромный плюс имеется - у тебя описан один лишь интерфейс без лишних подробностей, возможно с комментами, читателю (да даже тебе самому через неделю-две) в этом лего разбираться не парся тонны лапши вокруг необходимой инфы, которая ему вообще нафиг не нужна

kvpfs_2
()
Последнее исправление: kvpfs_2 (всего исправлений: 1)
Ответ на: комментарий от vbr

Шаблоны вошли в чат

hello_world.impl.hpp вошел за ними. Кто хочет написать нормально, тот напишет. Я когда вижу месиво in class inline методов вместе с реализацией там же на 100500 строк, то хочется блевать и вообще в этом не разбираться дальше, автор написал дерьмо

kvpfs_2
()
Последнее исправление: kvpfs_2 (всего исправлений: 1)
Ответ на: комментарий от kvpfs_2

Точно также можно и расто программу разделить на несколько крейтов после какого-то порога, и потом их собирать полностью параллельно. Я считаю что логический порог по функционалу/назначению/либе всегда будет более важным фактором чем ускорить сборку на сколько-то %.

интерфейс без лишних подробностей, возможно с комментами, читателю

В расте эта проблема решается хорошим генератором документации который идет вместе с комипилятором. В отличие от doxygen и прочих парсеров на уровне коментариев, он понимает весь синтаксис языка и делает верные ссылки на типы, и всю иерархию строит правильно, поддерживает markdown, и можно даже примеры использования метода в коментрарии описать и оно скомпилит его как юнит тест, удобная штука

pftBest ★★★★
()
Ответ на: комментарий от pftBest

В расте эта проблема решается хорошим генератором документации который идет вместе с комипилятором.

Хорошие доки - хорошо, да, компилятор это сделает лучше какого-нибудь doxygen, спора нет. Но нормально описанный интерфейс в хидере всё равно нужен - вот пишу я код, прыгнул по тагу на сущность, посмотрел на её интерфейс и контекст, прыгнул обратно, быстро и удобно. Не буду же я постояно в процессе кодописания открывать какую-то там доку сбоку и чего-то там смотреть, программисту нужен нормально написанный и удобно читаемый код

kvpfs_2
()
Последнее исправление: kvpfs_2 (всего исправлений: 1)
Ответ на: комментарий от kvpfs_2

В идеале да, но на практике что-то люди не умеют красиво писать, даже в больших и популярных либах всякое можно увидеть. Особенно выбешивает когда чередуют в разнобой поля класса с методами, приходится скролить сверху вниз чтобы хоть что-то найти.

pftBest ★★★★
()
Ответ на: комментарий от pftBest

Точно также можно и расто программу разделить на несколько крейтов после какого-то порога, и потом их собирать полностью параллельно.

Ну так ведь крейт должен быть полностью независим и быть самодостаточным. По-моему, это невыполнимая задача в рамках одного проекта с логически связанными частями, там через весь проект будут тянуться общие типы

kvpfs_2
()

Пришел к тому что Rust не умеет компилировать отдельные файлы в объектные, он делает это только для crate. Получается если у меня в crate много файлов, то мне при любом изменении надо будет все перекомпилировать, лол.

В Makefile все что можно написать это target: *.rs -> rustc *.rs -o target

MOPKOBKA ★★★★★
() автор топика
Последнее исправление: MOPKOBKA (всего исправлений: 3)
Ответ на: комментарий от kvpfs_2

По-моему, это невыполнимая задача в рамках одного проекта с логически связанными частями, там через весь проект будут тянуться общие типы

Крейт ведь может использовать типы других крейтов. Зависимость пишешь и всё.

monk ★★★★★
()
Ответ на: комментарий от MOPKOBKA

Получается если у меня в crate много файлов, то мне при любом изменении надо будет все перекомпилировать, лол.

делай каждый крейт из одного файла, будет как в других языках.

monk ★★★★★
()
Ответ на: комментарий от monk

Ага, и еще по отдельному репозиторию на каждый файл, что бы по best practicies, получится настоящий прогрессивный жаваскриптоподобный проект.

MOPKOBKA ★★★★★
() автор топика

А как пользоваться -C incremental? Нужны ли дополнительные телодвижения или достаточно указать на ./obj? У меня время компиляции с ним не сокращается при изменении одного файла из всего крейта.

MOPKOBKA ★★★★★
() автор топика
Ответ на: комментарий от grem

gcc-java тоже долго в составе gcc была.

Такой Hello World ему по силам, но std не реализована

extern "C" { 
    fn puts(s: *const i8); 
} 
 
#[no_mangle] 
pub extern "C" fn main() -> i32 { 
    unsafe { 
        puts("Hello World" as *const str as *const i8); 
    } 
    return 0; 
}   

MOPKOBKA ★★★★★
() автор топика
Ответ на: комментарий от kvpfs_2

И повторный разбор тех хидеров. Неизвестно, что хуже.

В принципе, крейты в основе дерева от хидеров мало отличаются (те же описания общих для проекта типов). А почти всё остальное параллелится.

monk ★★★★★
()
Ответ на: комментарий от monk

И повторный разбор тех хидеров. Неизвестно, что хуже.

Ну мы ведь все здесь чего-то компиляли, сколько уходит на создание одного объектного файла? Секунды в худшем случае. А благодаря отсутствию зависимостей (следовательно, и возможностям для параллелизации), компиляция одного файла == времени компиляции всех.

Я не говорю плохо о модулях, это норм для оборачивания в них неких логически законченных сущностей - библиотека целиком (std, например) или её относительно самостоятельных частей. Но они не заменят старых добрых хидер/имплементация. Если растаманы сочли, что это вдруг стало немодно и выпилили их, ну ссзб, успехов им

kvpfs_2
()
Ответ на: комментарий от kvpfs_2

Ну мы ведь все здесь чего-то компиляли, сколько уходит на создание одного объектного файла? Секунды в худшем случае.

Даже крошечный файл компилируется 8 секунд.

А благодаря отсутствию зависимостей (следовательно, и возможностям для параллелизации), компиляция одного файла == времени компиляции всех.

Если у тебя больше компьютеров, чем файлов, то да. А в разумном варианте, когда параллельных потоков пара десятков, а файлов пара тысяч (как при компиляции ядра), повторный разбор заголовков съест больше времени, чем будет выигрыш от параллельности.

A friend once (while bored at work), took his company’s application and put everything – all source and header files– into one big file. Compile time dropped from 3 hours to 7 minutes. (https://stackoverflow.com/questions/318398/why-does-c-compilation-take-so-long)

monk ★★★★★
()
Ответ на: комментарий от kvpfs_2

С другой стороны, если нужно макс производительность то придется включать LTO и это все сравняет.

А и еще вспомнил, много раз видел как делают pimpl паттерн только ради того чтобы не торчали хедеры наружу и не замедляли сборку всем кто пользуется классом. А это тоже не нулевое влияние на производительность, даже если потом lto включить то все равно не бесплатно.

pftBest ★★★★
()