Компилятор dotnet
создает две копии одного и того же исполняемого файла, и мои навыки работы с Google недостаточно хороши, чтобы понять, почему.
Например. в простом консольном проекте:
dotnet publish --configuration Release
производит bin/Release/net8.0/FizzBuzz и bin/Release/net8.0/publish/FizzBuzz, которые идентичны.
Я хочу создать один оптимизированный исполняемый файл и один кроссплатформенный исполняемый файл. Как мне это сделать?
Обновлено: Благодаря @winscripter я понял следующее:
dotnet publish -c .
изготовим:
bin/net8.0/
├── FizzBuzz (executable)
├── FizzBuzz.deps.json (not sure)
├── FizzBuzz.dll (cross-platform IL code)
├── FizzBuzz.pdb (debug symbols)
├── FizzBuzz.runtimeconfig.json (required for non stand-alone)
└── publish/ (a copy of the above files)
FizzBuzz.dll
и FizzBuzz.runtimeconfig.json
необходимы для исполняемого файла FizzBuzz
, который можно запустить непосредственно с помощью ./bin/net8.0/publish/FizzBuzz
.
FizzBuzz.dll
можно запускать кроссплатформенно с помощью dotnet bin/net8.0/publish/FizzBuzz.dll
. Для этого требуется только FizzBuzz.runtimeconfig.json
.
Остальные сгенерированные файлы для запуска программы не нужны.
Я почти уверен, что без указания опции runtime
для dotnet
оптимизированная сборка по умолчанию предназначена для моей платформы, т.е. Linux.
ldd
reports linux specific dependencies:
ldd bin/net8.0/publish/FizzBuzz
linux-vdso.so.1 (0x00007ffd260e0000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fe955acd000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fe955ac8000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fe955800000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fe95571e000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fe955a9b000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe955539000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe955b05000)
Я знаю, что существуют разные цели сборки (специфичные для ОС, SDK для dotnet и т. д.), но меня смущает множество вариантов.
Если вы дадите ссылку на https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-publish, предоставьте, пожалуйста, описание минусов вариантов, так как я их не понимаю.
Мой файл FizzBuzz.csproj:
<Project Sdk = "Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<AssemblyName>FizzBuzz</AssemblyName>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<!-- I added ErrorOnDuplicatePublishOutputFiles -->
<ErrorOnDuplicatePublishOutputFiles>true</ErrorOnDuplicatePublishOutputFiles>
</PropertyGroup>
</Project>
Я добавил <ErrorOnDuplicatePublishOutputFiles>
, чтобы посмотреть, изменит ли это что-нибудь. Это не так.
dotnet --version
8.0.301
uname -a
Linux kali 6.8.11-amd64 #1 SMP PREEMPT_DYNAMIC Kali 6.8.11-1kali2 (2024-05-30) x86_64 GNU/Linux
Спасибо @winscripter. Это отвечает на часть моего вопроса. dotnet build --configuration Release
создаст кроссплатформенный (но не оптимизированный для ОС) dll-файл (не исполняемый), который может быть запущен программой dotnet
. И это отвечает, почему существуют дубликаты. Теперь, как мне создать один оптимизированный исполняемый файл? Я полагаю, это означает, что я не могу создать кроссплатформенный исполняемый файл, но мне нужно использовать программу dotnet
для выполнения файла .dll.
Я не уверен, возможно ли опубликовать исполняемый файл, который может работать на нескольких системах одновременно. В этом случае вам нужно будет использовать dotnet publish
для публикации нескольких исполняемых файлов для нескольких систем. Итак, dotnet publish --runtime win-x64
для 64-разрядной версии Windows, dotnet publish --runtime linux-x64
для 64-разрядной версии Linux и т. д. С другой стороны, dotnet build
приводит к созданию dll, содержащей IL-код, который может работать в нескольких системах одновременно, но его необходимо выполнить с помощью команды dotnet
.
Это происходит по касательной, но вы предоставляете полезную информацию :) Единственный известный мне способ выполнить код IL в файле .dll — это использовать программу dotnet
. Какие еще варианты есть? Я использую Linux, поэтому это может помешать мне опробовать Windows. Тем не менее я хотел бы получить ответ на оставшуюся часть моего вопроса: как мне создать оптимизированный исполняемый файл для конкретной ОС? Скажем, для Linux, если это поможет. Теперь я знаю, что могу сделать это с помощью dotnet publish
, но не думаю, что мне действительно нужно все, что нужно опубликовать — могу ли я как-то минимизировать вывод?
На самом деле! Извини, @winscripter, после твоего последнего комментария мне следовало постараться немного усерднее. Думаю, я понял. Спасибо! Я все еще получаю много артефактов, но начинаю понимать, что они делают. Если вы превратите эти два пункта в ответ, я приму его.
На самом деле сейчас я начал использовать компилятор csc
из Mono. Он намного проще, чем dotnet
, но идеально подходит для моего случая использования. Это ускоряет освоение C#, потому что я мало что писал со времен C# 2.0 (много лет назад).
Что касается того, почему существует две копии исполняемого файла, см. этот ответ:
dotnet publish
собирает проект перед копированием двоичных файлов в выходной каталог. Файлы, которые вы видите в каталоге bin\Release\netcoreapp2.0\win-x64, являются результатом команды dotnet build. Вы можете проверить это, выполнив следующую команду:dotnet build --configuration Release --runtime win-x64
Что касается того, как опубликовать исполняемый файл для одновременного запуска на нескольких системах: я не думаю, что это возможно. Когда вы используете команду dotnet publish
, она генерирует исполняемый файл, специфичный для ОС (поэтому он будет работать только в одной операционной системе). Таким образом, вам потребуется опубликовать несколько исполняемых файлов, чтобы сделать приложение кроссплатформенным, например dotnet publish --runtime win-x64
для 64-разрядная версия Windows или dotnet publish --runtime linux-x64
для 64-разрядной версии Linux. Или используйте dotnet build
для создания dll-файла, содержащего IL-код, который может работать в нескольких системах одновременно, но может потребоваться его выполнение с помощью команды dotnet
.
Я перефразировал свой вопрос, чтобы было более понятно. Теперь я вижу, что было неясно, что я спрашивал, как создать два разных исполняемых файла, а не один, одновременно оптимизированный и кроссплатформенный.
Документ здесь — Обзор публикации приложений .NET. Прежде всего, существует два основных режима публикации: зависящий от платформы («по умолчанию») и автономный:
Оба режима публикации по умолчанию создают исполняемый файл для конкретной платформы. Приложения, зависящие от платформы, можно создавать без исполняемого файла, и эти приложения являются кроссплатформенными.
Вы приказываете — dotnet publish --configuration Release
результаты в зависимом от платформы исполняемом файле для текущей платформы:
Публикация приложения как зависимого от платформы создает кросс-платформенный двоичный файл в виде dll-файла и исполняемый файл для конкретной платформы, предназначенный для вашей текущей платформы. Dll является кроссплатформенной, а исполняемый файл — нет. Например, если вы публикуете приложение с именем word_reader и предназначено для Windows, вместе с word_reader.dll создается исполняемый файл word_reader.exe. При использовании Linux или macOS вместе с word_reader.dll создается исполняемый файл word_reader.
Таким образом, у вас будет исполняемый файл FizzBuzz
(для конкретной ОС) и FizzBuzz.dll
, который на самом деле является кроссплатформенным и может запускаться с помощью команды dotnet
.
Обратите внимание, что .dll на самом деле будет содержать CIL (общий промежуточный язык) код , который будет фактически скомпилирован в код, специфичный для платформы, когда приложение будет запускаться ( через JIT-компилятор , который является частью время выполнения). Бывают случаи, когда это нежелательно («одноразовые» консольные приложения, возможно, лямбды AWS и т. д.). В этом случае вы можете рассмотреть либо компиляцию ReadyToRun , либо собственное развертывание AOT (в настоящее время поддерживаются не все типы приложений).
Также стоит упомянуть — есть опция Однофайловое развертывание, которая может пригодиться в некоторых случаях.