Closed5

fsc(F#のCompiler)から Hello, World! したかった話

四ツ山伊吹四ツ山伊吹

モチベーション

Cでは、c99 (standard C language compiler) を使って

$ c99 hello.c

として実行可能なバイナリファイルを生成する。

F#でも同様にして、単一のソースプログラムをコンパイラーに食わせてターゲットプログラムを生成するというのをやりたかった。

結論

無理そう

四ツ山伊吹四ツ山伊吹

F#のCompilerの起動(macOSの場合)

.NET SDKのインストールを終えていれば

$ dotnet --list-sdks

とすることで、インストール済みのSDKのパスを得られる。

ここでシェル変数をsdk='/usr/local/share/dotnet/sdk/<VERSION>'とし、以降はこのシェル変数を参照するものとする。

コンパイラーのパスは${sdk}/FSharp/fsc.dllとなる。

fsc.dllは.NETアプリケーションの一種であるので、dotnetコマンドを介して起動する必要がある。

$ dotnet ${sdk}/FSharp/fsc.dll --version
Microsoft (R) F# Compiler version 12.0.3.0 for F# 6.0
...
$ dotnet ${sdk}/FSharp/fsc.dll --help
Microsoft (R) F# Compiler version 12.0.3.0 for F# 6.0
Copyright (c) Microsoft Corporation. All Rights Reserved.


		- OUTPUT FILES -
--out:<file>                             Name of the output file (Short form: -o)
--target:exe                             Build a console executable
--target:winexe                          Build a Windows executable
--target:library                         Build a library (Short form: -a)
--target:module                          Build a module that can be added to another assembly
--delaysign[+|-]                         Delay-sign the assembly using only the public portion of the strong name key
--publicsign[+|-]                        Public-sign the assembly using only the public portion of the strong name key, and mark the assembly as signed
--doc:<file>                             Write the xmldoc of the assembly to the given file
--keyfile:<file>                         Specify a strong name key file
--platform:<string>                      Limit which platforms this code can run on: x86, Itanium, x64, anycpu32bitpreferred, or anycpu. The default is
                                         anycpu.
--nooptimizationdata                     Only include optimization information essential for implementing inlined constructs. Inhibits cross-module
                                         inlining but improves binary compatibility.
--nointerfacedata                        Don't add a resource to the generated assembly containing F#-specific metadata
--sig:<file>                             Print the inferred interface of the assembly to a file
--allsigs                                Print the inferred interfaces of all compilation files to associated signature files
--nocopyfsharpcore                       Don't copy FSharp.Core.dll along the produced binaries


		- INPUT FILES -
--reference:<file>                       Reference an assembly (Short form: -r)
--compilertool:<file>                    Reference an assembly or directory containing a design time tool (Short form: -t)


		- RESOURCES -
--win32icon:<file>                       Specify a Win32 icon file (.ico)
--win32res:<file>                        Specify a Win32 resource file (.res)
--win32manifest:<file>                   Specify a Win32 manifest file
--nowin32manifest                        Do not include the default Win32 manifest
--resource:<resinfo>                     Embed the specified managed resource
--linkresource:<resinfo>                 Link the specified resource to this assembly where the resinfo format is <file>[,<string name>[,public|private]]


		- CODE GENERATION -
--debug[+|-]                             Emit debug information (Short form: -g)
--debug:{full|pdbonly|portable|embedded} Specify debugging type: full, portable, embedded, pdbonly. ('full' is the default if no debuggging type specified
                                         and enables attaching a debugger to a running program, 'portable' is a cross-platform format, 'embedded' is a
                                         cross-platform format embedded into the output file).
--embed[+|-]                             Embed all source files in the portable PDB file
--embed:<file;...>                       Embed specific source files in the portable PDB file
--sourcelink:<file>                      Source link information file to embed in the portable PDB file
--optimize[+|-]                          Enable optimizations (Short form: -O)
--tailcalls[+|-]                         Enable or disable tailcalls
--deterministic[+|-]                     Produce a deterministic assembly (including module version GUID and timestamp)
--pathmap:<path=sourcePath;...>          Maps physical paths to source path names output by the compiler
--crossoptimize[+|-]                     Enable or disable cross-module optimizations


		- ERRORS AND WARNINGS -
--warnaserror[+|-]                       Report all warnings as errors
--warnaserror[+|-]:<warn;...>            Report specific warnings as errors
--warn:<n>                               Set a warning level (0-5)
--nowarn:<warn;...>                      Disable specific warning messages
--warnon:<warn;...>                      Enable specific warnings that may be off by default
--consolecolors[+|-]                     Output warning and error messages in color


		- LANGUAGE -
--langversion:{?|version|latest|preview} Display the allowed values for language version, specify language version such as 'latest' or 'preview'
--checked[+|-]                           Generate overflow checks
--define:<string>                        Define conditional compilation symbols (Short form: -d)
--mlcompatibility                        Ignore ML compatibility warnings


		- MISCELLANEOUS -
--nologo                                 Suppress compiler copyright message
--version                                Display compiler version banner and exit
--help                                   Display this usage message (Short form: -?)
--@<file>                                Read response file for more options


		- ADVANCED -
--codepage:<n>                           Specify the codepage used to read source files
--utf8output                             Output messages in UTF-8 encoding
--preferreduilang:<string>               Specify the preferred output language culture name (e.g. es-ES, ja-JP)
--fullpaths                              Output messages with fully qualified paths
--lib:<dir;...>                          Specify a directory for the include path which is used to resolve source files and assemblies (Short form: -I)
--simpleresolution                       Resolve assembly references using directory-based rules rather than MSBuild resolution
--targetprofile:<string>                 Specify target framework profile of this assembly. Valid values are mscorlib, netcore or netstandard. Default -
                                         mscorlib
--baseaddress:<address>                  Base address for the library to be built
--checksumalgorithm:{SHA1|SHA256}        Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256
                                         (default)
--noframework                            Do not reference the default CLI assemblies by default
--standalone                             Statically link the F# library and all referenced DLLs that depend on it into the assembly being generated
--staticlink:<file>                      Statically link the given assembly and all referenced DLLs that depend on this assembly. Use an assembly name e.g.
                                         mylib, not a DLL name.
--pdb:<string>                           Name the output debug file
--highentropyva[+|-]                     Enable high-entropy ASLR
--subsystemversion:<string>              Specify subsystem version of this assembly
--quotations-debug[+|-]                  Emit debug information in quotations
四ツ山伊吹四ツ山伊吹

はじめてのコンパイル

そういうわけで以下のようなhello.fsを作成し、

hello.fs
printfn "Hello, World!"

コンパイルしてみる。

$ dotnet ${sdk}/FSharp/fsc.dll hello.fs

すると普通に失敗する。

error FS0082: Could not resolve this reference. Could not locate the assembly "System.Runtime.Remoting.dll". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors. (Code=MSB3245)

error FS0082: Could not resolve this reference. Could not locate the assembly "System.Runtime.Serialization.Formatters.Soap.dll". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors. (Code=MSB3245)

error FS0082: Could not resolve this reference. Could not locate the assembly "System.Web.Services.dll". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors. (Code=MSB3245)

error FS0082: Could not resolve this reference. Could not locate the assembly "System.Windows.Forms.dll". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors. (Code=MSB3245)

🧐

四ツ山伊吹四ツ山伊吹

調査

https://github.com/dotnet/fsharp/issues/10614#issuecomment-743317627

This behaviour is by design. The only reliable way to build a working coreclr app is by using the DotNET Sdk. the ```fsc program.fs```` build gesture doesn't work reliably. The reason for this is that computing the references and producing the correct runtime outputs are not built into the compiler. The compiler takes inut files and produces output files, adapting to different platforms is the work of the Sdk.

It would be fair to say that we take a pretty good crack at some of this work in fsi.exe, but we still rely on the sdk for doing most of that work.

On Linux the dotnet sdk has a way of locating the desktop binaries so wrap your build in an fsproj.


The command line for a simple hello, world processed by the dotnetsdk looks like, and this still won't produce runnable code it requires the build to have put the necessary dependencies and config files in the output directory.

Sure, I could probably go through and remove a ton of these lines and it would still compile, but they are all necessary to cover the main developer use case we build for. I think you'll find that C# has the exact same requirements.


https://qiita.com/7shi/items/6bc57ddde5a06e526496

四ツ山伊吹四ツ山伊吹

無理そう

モチベーションで述べたやり方ではコンパイルができなさそうというのがわかった。

基本に則って、.fsprojを基にしてやっていくことにする。

このスクラップは2022/05/15にクローズされました