Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dotnet-compile #4319

Closed
richlander opened this issue Oct 15, 2015 · 14 comments
Closed

dotnet-compile #4319

richlander opened this issue Oct 15, 2015 · 14 comments
Assignees
Milestone

Comments

@richlander
Copy link
Member

dotnet-compile

NAME
dotnet-compile -- Compiles source files to a binary format and saves to a target file.

SYNOPSIS
dotnet compile [options]

DESCRIPTION
The compile command compiles source files to a binary file, either IL byte code or native machine code, depending on the options provided. The default option is compilation to IL byte code, but may change to native compilation as that toolchain matures.

The default IL [--il] output is a PE32 exe [exe], with the default extension of ".exe" on all OSes. The exe must include a static main entry point, or it is an error. The dll [dll] output option has the default extension of ".dll".

The IL exe output type needs a runtime host to execute. The IL exe output type also copies a host to the output directory. The host is renamed to the name of the exe. For example, if the file is intended to be "foo" (-o foo), then the host will be called foo, with the appropriate default native file extension fo the OS (see the native file extensions, below). The PE32 exe will be called "[filename]"-app.exe". In this case, it would be called "foo-app.exe".

The default native [--native] output is a native exe that conforms to the architecture of the underlying operating system (i.e. running on 64-bit OS will produce a native 64-bit exe). This can be overriden via the --arch switch and specifying the wanted architecture. The executable has a default extension of "" on Linux and OS X and ".exe" on Windows. The source must include a static void main entry point, or it is an error, unless otherwise specified in the project.json. The dynamic library [dylib] output option has the default extension of ".so" on Linux/UNIX, ".dynlib" on OS X and ".dll" on Windows. The static library [staticlib] option has the default extension of ".a" on Linux, UNIX and OS X and ".lib" on Windows.

This command relies on the following artifacts: source files, project.json project file, restore.json temporary file and restored NuGet dependencies. In the case that an app depends on only the .NET Standard Library, then the project.json and restore.json file can be inferred and no additional NuGet dependencies are required. Other cases where these files are not provided or they do not match (more on that later) are error states.

The project.json file represents and describes the project. It can contain several setting, which are described in the Build. The most important information in the project.json file are the root (not transitive) NuGet dependencies and the files to be compiled. By default, this is a wildcard -- "*.cs". It supports both inclusion and exclusion semantics.

The restore.json file is expanded form of the project.json file. It includes the transitive closure of the project, per framework. It is produced by a NuGet client, typically by using the dotnet restore command. The restore.json file can be used by tools to safely determine the closure of dependencies, without having to manually calculate them. This file is only intended for tools, is temporary and should not be checked into source control. It should be present in .gitignore files.

It is important to know that a restore.json is invalid given that a project.json has been changed. The restore.json has enough information to determine this state given a project.json. The compile command validates this state and will error if the restore.json is invalid.

The compile command relies on NuGet dependencies for compilation, as references. These are expected to be found in the user-local NuGet cache (typically location here). It is an error state if a given NuGet package is not found.

Output files, including temporary files, are written to the child bin folder, which will be created if it doesn't exist. Files will be overwritten as needed.

Options

-n, --native [exe | dynlib | lib]
Compiles source to native machine code, for the local machine. The default is a native executable. The default exe extension is no extension and ".exe" on Windows. The default dynlib extension is ".a", ".dynlib" on OS X and ".dll" on Windows.

-a, --arch [x86 | x64]
Determines the architecture of the binary that --native produces. Valid values are x86 for 32-bit and x64 for 64-bit.

--il [exe | dll]
Compiles source to IL byte code, which is (typically) portable across machine types. The default output is a PE32 exe, with the default extension of ".exe" on all OSes. The exe must include a static main entry point, or it is an error. The DLL output option has the default extension of ".dll".

-o, --output filename
Specifies the filename to be used. It is an error not to specify an output filename. If no extension is provided, the default one is provided for the output type.

-r, --restore
Restores the project before attempting to compile the project.

-v, --verbose
Prints verbose logging information, to follow the flow of execution of the command.

@ellismg
Copy link
Contributor

ellismg commented Oct 15, 2015

In the case of native compilation, the final executable is written to the project folder (same location as project.json). In the case of native compilation, a single final file is generated, making it very convenient to run and to manage.

This seems like a bad default to me. If I understand correctly, the output is going to placed next to my project.json which presumably is under source control. Git, for example, will see this as an untracked file and say things are dirty.

@richlander
Copy link
Member Author

@ellismg That's also what .gitignore is for.

This is something that we can discuss and see what user experience we want.

@ellismg
Copy link
Contributor

ellismg commented Oct 15, 2015

@richlander Not having a common .gitignore that can be shared across different projects feels like it's going to be annoying. Do you expect folks are going to "echo MyGreatProject >> .gitignore" after git initing? Maybe if you did this as part of dotnet init it would be tolerable.

Littering files across folders that are usually filled with source and then expecting folks to craft complex .gitignore files to deal with it doesn't feel very user friendly to me. Better to put everything in something like bin\ or obj\ which I can ignore easily.

Just my two cents...

@richlander
Copy link
Member Author

@ellismg Let's go with your plan. Documentation has been updated.

@davidfowl
Copy link
Member

I think --il shouldn't be a flag really.

-r, --restore
Restores the project before attempting to compile the project.

This is weird. Do we need this?

@richlander
Copy link
Member Author

@davidfowl Isn't it natural to have flags for all the options and then just specify which ones are the defaults. Can you should me an example of such a case on another tool? I was using git as a mode for the docs, for example.

I added the --restore option after we talked about the "do everything" option. We could add it outside as "dotnet doeverything", which is I think what you were suggesting. I guess that's better from a layering perspective. I was planing on having convenience options for compile and run. Would you propose doeverythingrun and doeverythingcompile or doeverything --mode??

@TheRealPiotrP
Copy link
Contributor

I mentioned the --il flag in another context as well. The confusion is this: we need to produce il for both the --il and the --n scenarios. Since there is no way around it, the flag creates ambiguity. For example, if we say --n without --il is the expectation that we produce the il, compile to native, and then delete the il? Seems bad.

@richlander
Copy link
Member Author

@piotrpMSFT I talked to @davidfowl about this. He had similar feedback. I'm splitting this into two commands. I think that should solve it. Good feedback.

That all said, we'll need to do what you propose at first, that is nativecompile will wrap compile and produce an IL binary that needs to be deleted. No?

@TheRealPiotrP
Copy link
Contributor

I prefer having a layout that includes all build artifacts and that allows us to repeat sub-steps in the sequence. Deleting artifacts along the way starts to seem like magic, something I'd enjoy avoiding.

I do agree that having all of these artifacts can be confusing, however. Isn't that the point of the Publish step? Scavenge the artifacts folks care about and put them in a place that's easy to use? Even Native Compilation is likely to produce some side-artifacts that are useful during build/diagnostics but not useful after publishing...

In my minds eye, the developer interacts with wrapper commands that chain together atomic commands. If any of the base commands become so useful that they actually 'do something' then I think we missed the boat on decomposability. Take a look at #4316 for my thoughts on this.

@richlander
Copy link
Member Author

@piotrpMSFT I think you are right. I hadn't thought about it deeply enough.

@gkhanna79
Copy link
Member

The exe must include a static main entry point, or it is an error.
This is expected of the managed compiler. Is there a specific reason this is called out?

The PE32 exe will be called "[filename]"-app.exe". In this case, it would be called "foo-app.exe".
This is different from what CoreConsole does today (for both Windows and Unix). Is this a new convention we are defining and expect to update CoreConsole with it or are we planning to maintain multiple? IMHO, it will be great to have a single convention.

The default native [--native] output is a native 64-bit exe [exe] for the local OS.
This implies that we always carry/deploy toolchain/runtime for all architectures but the default output architecture will be 64bit. Is that correct understanding? If so, are we going to support a "--arch" switch to specify alternative architectures to compile for? Also, what happens on a 32bit only box - will dotnet compile handle it?

@richlander
Copy link
Member Author

@gkhanna79 The focus on 64-bit was related to us only having 64-bit until now. If we've now added 32-bit, we should fix the help doc.

This is probably an example where the help doc is being too much of a 'spec'. @blackdwarf Can you change the "man page" to account for both 32- and 64-bit scenarios? That was a mistake on my part.

@blackdwarf
Copy link

Changed. The default behavior is now to detect the OS arch and by default produce a native binary with that arch, or it can be overriden with the --arch switch.

@blackdwarf blackdwarf self-assigned this Dec 15, 2015
@blackdwarf
Copy link

We moved these specs from the issues to actual MD files in the repo, so will close this one. Please reopen if needed.

wli3 referenced this issue in wli3/cli Jul 14, 2017
Adding a publish E2E test using TestAssets
wli3 referenced this issue in wli3/cli Sep 10, 2018
Update coresetup, coresetup to preview1-26813-02, preview1-26813-02, respectively (master)
@msftgits msftgits transferred this issue from dotnet/cli Jan 31, 2020
@msftgits msftgits added this to the Backlog milestone Jan 31, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants