@@ -74,14 +74,46 @@ module DotNetTaskTypes =
7474 FailOnError: bool
7575 }
7676
77+ /// <summary >
78+ /// Fsc (F# compiler) task settings.
79+ /// </summary >
80+ type FscSettingsType = {
81+ /// Limits which platforms this code can run on. The default is anycpu.
82+ Platform: TargetPlatform
83+ /// Specifies the format of the output file.
84+ Target: TargetType
85+ /// Specifies the output file name (default: base name of file with main class or first file).
86+ Out: Artifact
87+ /// Source files.
88+ Src: Fileset
89+ /// References metadata from the specified assembly files.
90+ Ref: Fileset
91+ /// References the specified assemblies from GAC.
92+ RefGlobal: string list
93+ /// Embeds the specified resource.
94+ Resources: ResourceFileset list
95+ /// Defines conditional compilation symbols.
96+ Define: string list
97+ /// Allows unsafe code.
98+ Unsafe: bool
99+ /// Target .NET framework
100+ TargetFramework: string
101+ /// Custom command-line arguments
102+ CommandArgs: string list
103+ /// Build fails on compile error.
104+ FailOnError: bool
105+
106+ Tailcalls: bool
107+ }
108+
77109[<AutoOpen>]
78110module DotnetTasks =
79111
80112 open CommonTasks.impl
81113
82114 /// Default setting for CSC task so that you could only override required settings
83115 let CscSettings = {
84- Platform = AnyCpu
116+ CscSettingsType. Platform = AnyCpu
85117 Target = Auto // try to resolve the type from name etc
86118 Out = Artifact.Undefined
87119 Src = Fileset.Empty
@@ -96,6 +128,7 @@ module DotnetTasks =
96128 }
97129
98130 module internal Impl =
131+ begin
99132 /// Escapes argument according to CSC.exe rules (see http://msdn.microsoft.com/en-us/library/78f4aasd.aspx )
100133 let escapeArgument ( str : string ) =
101134 let escape c s =
@@ -179,24 +212,26 @@ module DotnetTasks =
179212 ( Path.ChangeExtension( res, " .resources" ), tempfile, true )
180213 | ( res, file) ->
181214 ( res, file, false )
182- // end of Impl module
183-
184- /// C# compiler task
185- let Csc settings =
186-
187- let outFile = settings.Out
188215
189216 let resolveTarget ( name : string ) =
190217 if name.EndsWith ( " .dll" , System.StringComparison.OrdinalIgnoreCase) then Library else
191218 if name.EndsWith ( " .exe" , System.StringComparison.OrdinalIgnoreCase) then Exe else
192219 Library
193220
194- let rec targetStr = function
221+ let rec targetStr fileName = function
195222 | AppContainerExe -> " appcontainerexe" | Exe -> " exe" | Library -> " library" | Module -> " module" | WinExe -> " winexe" | WinmdObj -> " winmdobj"
196- | Auto -> outFile.Name |> resolveTarget |> targetStr
223+ | Auto -> fileName |> resolveTarget |> targetStr fileName
224+
197225 let platformStr = function
198226 | AnyCpu -> " anycpu" | AnyCpu32Preferred -> " anycpu32preferred" | ARM -> " arm" | X64 -> " x64" | X86 -> " x86" | Itanium -> " itanium"
199-
227+
228+ end // end of Impl module
229+
230+ /// C# compiler task
231+ let Csc ( settings : CscSettingsType ) =
232+
233+ let outFile = settings.Out
234+
200235 action {
201236 let! options = getCtxOptions()
202237 let getFiles = toFileList options.ProjectRoot
@@ -241,8 +276,8 @@ module DotnetTasks =
241276 seq {
242277 yield " /nologo"
243278
244- yield " /target:" + targetStr settings.Target
245- yield " /platform:" + platformStr settings.Platform
279+ yield " /target:" + Impl. targetStr outFile.Name settings.Target
280+ yield " /platform:" + Impl. platformStr settings.Platform
246281
247282 if settings.Unsafe then
248283 yield " /unsafe"
@@ -396,7 +431,7 @@ module DotnetTasks =
396431 let! dotnetFwk = getVar " NETFX"
397432 let fwkInfo = DotNetFwk.locateFramework dotnetFwk
398433
399- let pfx = " msbuild" // TODO thread/index
434+ let pfx = " msbuild"
400435
401436 let verbosityKey = function | Quiet -> " q" | Minimal -> " m" | Normal -> " n" | Detailed -> " d" | Diag -> " diag"
402437
@@ -443,3 +478,134 @@ module DotnetTasks =
443478 if settings.FailOnError then failwithf " Exiting due to FailOnError set on '%s '" pfx
444479 ()
445480 }
481+
482+ /// <summary >
483+ /// Default settings for Fsc task.
484+ /// </summary >
485+ let FscSettings = {
486+ FscSettingsType.Platform = AnyCpu
487+ FscSettingsType.Target = Auto
488+ Out = Artifact.Undefined
489+ Src = Fileset.Empty
490+ Ref = Fileset.Empty
491+ RefGlobal = []
492+ Resources = []
493+ Define = []
494+ Unsafe = false
495+ TargetFramework = null
496+ CommandArgs = []
497+ FailOnError = true
498+
499+ Tailcalls = true
500+ }
501+
502+ /// F# compiler task
503+ let Fsc ( settings : FscSettingsType ) =
504+
505+ let outFile = settings.Out
506+
507+ action {
508+ let! options = getCtxOptions()
509+ let getFiles = toFileList options.ProjectRoot
510+
511+ let resinfos = settings.Resources |> List.collect ( Impl.collectResInfo options.ProjectRoot) |> List.map Impl.compileResxFiles
512+ let resfiles =
513+ List.ofSeq <|
514+ query {
515+ for (_, file, istemp) in resinfos do
516+ where ( not istemp)
517+ select ( file)
518+ }
519+
520+ let ( Filelist src ) = settings.Src |> getFiles
521+ let ( Filelist refs ) = settings.Ref |> getFiles
522+
523+ do ! needFiles ( Filelist ( src @ refs @ resfiles))
524+
525+ // TODO implement support for targeting various frameworks
526+ let! globalTargetFwk = getVar " NETFX-TARGET"
527+ let targetFramework =
528+ match settings.TargetFramework, globalTargetFwk with
529+ | s, _ when s <> null && s <> " " -> s
530+ | _, Some s when s <> " " -> s
531+ | _ -> null
532+
533+ let ( globalRefs , nostdlib , noconfig ) =
534+ match targetFramework with
535+ | null ->
536+ let mapfn = (+) " /r:"
537+ // TODO provide an option for user to explicitly specify all grefs (currently csc.rsp is used)
538+ ( settings.RefGlobal |> List.map mapfn), false , false
539+ | tgt ->
540+ let fwk = Some tgt |> DotNetFwk.locateFramework in
541+ let lookup = DotNetFwk.locateAssembly fwk
542+ let mapfn = ( fun name -> " /r:" + ( lookup name))
543+
544+ //do! writeLog Info "Using libraries from %A" fwk.AssemblyDirs
545+
546+ ( " mscorlib.dll" :: settings.RefGlobal |> List.map mapfn), true , true
547+
548+ let args =
549+ seq {
550+ if noconfig then
551+ yield " /noconfig"
552+ yield " /nologo"
553+
554+ yield " /target:" + Impl.targetStr outFile.Name settings.Target
555+ //yield "/platform:" + Impl.platformStr settings.Platform
556+
557+ if settings.Unsafe then
558+ yield " /unsafe"
559+
560+ if nostdlib then
561+ yield " /nostdlib+"
562+
563+ if not outFile.IsUndefined then
564+ yield sprintf " /out:%s " outFile.FullName
565+
566+ if not ( List.isEmpty settings.Define) then
567+ yield " /define:" + ( settings.Define |> String.concat " ;" )
568+
569+ yield ! src |> List.map ( fun f -> f.FullName)
570+
571+ yield ! refs |> List.map (( fun f -> f.FullName) >> (+) " /r:" )
572+ yield ! globalRefs
573+
574+ yield ! resinfos |> List.map ( fun ( name , file , _ ) -> sprintf " /res:%s ,%s " file.FullName name)
575+ yield ! settings.CommandArgs
576+ }
577+
578+ let! dotnetFwk = getVar " NETFX"
579+ let fwkInfo = DotNetFwk.locateFramework dotnetFwk
580+
581+ if Option.isNone fwkInfo.FscTool then
582+ do ! writeLog Error " ('%s ') failed: F# compiler not found" outFile.Name
583+ if settings.FailOnError then failwithf " Exiting due to FailOnError set on '%s '" outFile.Name
584+
585+ let ( Some fsc ) = fwkInfo.FscTool
586+
587+ do ! writeLog Info " compiling '%s ' using framework '%s '" outFile.Name fwkInfo.Version
588+ do ! writeLog Debug " Command line: '%s %s '" fsc ( args |> Seq.map Impl.escapeArgument |> String.concat " \r\n\t " )
589+
590+ let options = {
591+ SystemOptions with
592+ LogPrefix = " [FSC] "
593+ StdOutLevel = Level.Verbose // consider standard compiler output too noisy
594+ EnvVars = fwkInfo.EnvVars
595+ }
596+ let! exitCode = _ system options fsc ( args |> String.concat " " )
597+
598+ do ! writeLog Level.Verbose " Deleting temporary files"
599+ seq {
600+ yield ! query {
601+ for (_, file, istemp) in resinfos do
602+ where istemp
603+ select file.FullName
604+ }
605+ }
606+ |> Seq.iter File.Delete
607+
608+ if exitCode <> 0 then
609+ do ! writeLog Error " ('%s ') failed with exit code '%i '" outFile.Name exitCode
610+ if settings.FailOnError then failwithf " Exiting due to FailOnError set on '%s '" outFile.Name
611+ }
0 commit comments