Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,11 @@ jobs:

- name: Fable Tests - Python (linux)
if: matrix.platform == 'ubuntu-latest'
run: ./build.sh test python --skip-fable-library
run: ./build.sh test python

- name: Fable Tests - Python (Windows)
if: matrix.platform == 'windows-latest'
run: .\build.bat test python --skip-fable-library
run: .\build.bat test python

# Separate build job for Rust (will run in parallel)
build-rust:
Expand Down Expand Up @@ -209,7 +209,7 @@ jobs:
run: ./build.sh fable-library --rust

- name: Fable Tests - Rust
run: ./build.sh test rust --skip-fable-library --${{ matrix.test }}
run: ./build.sh test rust --${{ matrix.test }}

# Separate build job for Dart
build-dart:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -232,3 +232,5 @@ Cargo.lock

# This file is copied as part of the Restore task
tests/React/Components.Copied.fs

.build-cache/
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The build system is implemented in F# at `src/Fable.Build/`. All commands go thr
# Run tests (targets: javascript, typescript, python, dart, rust, beam, integration)
./build.sh test javascript
./build.sh test javascript --watch # Watch mode (recompile on changes)
./build.sh test javascript --skip-fable-library # Skip fable-library rebuild (only if fable-library source is unchanged)
./build.sh test javascript --force-fable-library # Force fable-library rebuild (needed if you modified Fable compiler to fix the generation of `src/fable-library-*/**/*.fs` files)

# Python-specific options
./build.sh test python --skip-fable-library-core # Skip slow Rust extension + .pyi rebuild (Python only)
Expand All @@ -29,7 +29,7 @@ The build system is implemented in F# at `src/Fable.Build/`. All commands go thr
./build.sh quicktest javascript # Also: typescript, python, dart, rust, beam
```

`--skip-fable-library` is safe when changes are only in `src/Fable.Transforms/` or other compiler code. If you modified runtime library source (e.g., `src/fable-library-py/`, `src/fable-library-ts/`), do not skip. If you already ran `./build.sh fable-library` separately, use `--skip-fable-library` when running tests right afterwards to avoid rebuilding.
In most cases, you should not need to use `--force-fable-library`. Only use it if you modified compiler code that affects how F# files used in `src/fable-library-*/` are generated (e.g., changes to `FSharp2Fable.fs` that affect how F# AST is transformed into Fable AST for library files).

Build output goes to `temp/`: transpiled runtime libraries in `temp/fable-library-<target>/` and test output in `temp/tests/<target>/` (e.g., `temp/fable-library-beam/` and `temp/tests/beam/`).

Expand Down
4 changes: 3 additions & 1 deletion src/Fable.Build/Fable.Build.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="Utils.fs" />
<Compile Include="Utils/LastVersionFinder.fs" />
<Compile Include="Workspace.fs" />
<Compile Include="Utils/LastVersionFinder.fs" />
<Compile Include="Utils/IncrementalBuild.fs" />
<Compile Include="SimpleExec.Extensions.fs" />
<Compile Include="FableLibrary/Core.fs" />
<Compile Include="FableLibrary/Python.fs" />
Expand Down Expand Up @@ -46,6 +47,7 @@
<PackageReference Include="EasyBuild.Tools" Version="6.0.0" />
<PackageReference Include="Fake.IO.FileSystem" Version="6.1.4" />
<PackageReference Include="FsToolkit.ErrorHandling" Version="5.2.0" />
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" Version="10.0.5" />
<PackageReference Include="SimpleExec" Version="13.0.0" />
<PackageReference Include="Thoth.Json.Net" Version="12.0.0" />
<PackageReference Include="Semver" Version="3.0.0" />
Expand Down
7 changes: 6 additions & 1 deletion src/Fable.Build/FableLibrary/Beam.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ type BuildFableLibraryBeam() =
Path.Combine("src", "fable-library-beam"),
Path.Combine("src", "fable-library-beam"),
Path.Combine("temp", "fable-library-beam"),
Path.Combine("temp", "fable-library-beam")
Path.Combine("temp", "fable-library-beam"),
[
Path.Combine("src", "fable-library-beam", "**", "*.erl")
Path.Combine("src", "fable-library-beam", "**", "*.fs")
Path.Combine("src", "fable-library-ts", "**", "*.fs")
]
)

override this.CopyStage() =
Expand Down
92 changes: 56 additions & 36 deletions src/Fable.Build/FableLibrary/Core.fs
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
namespace Build.FableLibrary

open BlackFox.CommandLine
open Fake.IO
open System.IO
open Build.Utils
open Build.Utils
open System.Diagnostics
open SimpleExec
open Microsoft.Extensions.FileSystemGlobbing
open Microsoft.Extensions.FileSystemGlobbing.Abstractions

/// <summary>
/// Building fable-library is similar enough for all the targets
/// that we can use this class to standardise the process.
/// </summary>
type BuildFableLibrary
(language: string, libraryDir: string, sourceDir: string, buildDir: string, outDir: string, ?fableLibArg: string)
(
language: string,
libraryDir: string,
sourceDir: string,
buildDir: string,
outDir: string,
inputPatterns: string list,
?fableLibArg: string
)
=

// It seems like the different target have a different way of supporting
Expand Down Expand Up @@ -62,37 +69,50 @@ type BuildFableLibrary

tryDelete 3

member this.Run(?skipIfExist: bool) =
member this.Run(?forceBuild: bool) =
let toConsole (s: string) = System.Console.WriteLine(s)

let skipIfExist = defaultArg skipIfExist false

if skipIfExist && Directory.Exists outDir then
"Skipping Fable build stage" |> toConsole

else

"Cleaning build directory" |> toConsole

this.deleteDirectoryRobust buildDir

"Building Fable.Library" |> toConsole

let args =
CmdLine.appendRaw sourceDir
>> CmdLine.appendPrefix "--outDir" outDir
>> CmdLine.appendPrefix "--fableLib" fableLibArg
>> CmdLine.appendPrefix "--lang" language
>> CmdLine.appendPrefix "--exclude" "Fable.Core"
>> CmdLine.appendPrefix "--define" "FABLE_LIBRARY"
>> CmdLine.appendRaw "--noCache"
// Target implementation can require additional arguments
>> this.FableArgsBuilder

Command.Fable(args)

"Copy stage" |> toConsole
this.CopyStage()

"Post Fable build stage" |> toConsole
this.PostFableBuildStage()
let matcher = new Matcher()
matcher.AddIncludePatterns(inputPatterns)
// Ignore well-known build output folders from MSBuild
matcher.AddExcludePatterns([ "**/obj/**"; "**/bin/**" ])

let directoryInfo = DirectoryInfo(Path.Resolve())
let dirWrapper = DirectoryInfoWrapper(directoryInfo)

let inputFiles =
matcher.Execute(dirWrapper).Files
|> Seq.map (fun file -> Path.Combine(directoryInfo.FullName, file.Path))
|> Seq.toList

IncrementalBuild.run
$"fable-library-%s{this.Language}"
(defaultArg forceBuild false)
inputFiles
[ Path.Resolve(this.OutDir) ]
(fun () ->
"Cleaning build directory" |> toConsole

this.deleteDirectoryRobust buildDir

"Building Fable.Library" |> toConsole

let args =
CmdLine.appendRaw sourceDir
>> CmdLine.appendPrefix "--outDir" outDir
>> CmdLine.appendPrefix "--fableLib" fableLibArg
>> CmdLine.appendPrefix "--lang" language
>> CmdLine.appendPrefix "--exclude" "Fable.Core"
>> CmdLine.appendPrefix "--define" "FABLE_LIBRARY"
>> CmdLine.appendRaw "--noCache"
// Target implementation can require additional arguments
>> this.FableArgsBuilder

Command.Fable(args)

"Copy stage" |> toConsole
this.CopyStage()

"Post Fable build stage" |> toConsole
this.PostFableBuildStage()
)
4 changes: 4 additions & 0 deletions src/Fable.Build/FableLibrary/Dart.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ type BuildFableLibraryDart() =
Path.Combine("src", "fable-library-dart"),
Path.Combine("temp", "fable-library-dart"),
Path.Combine("temp", "fable-library-dart"),
[
Path.Combine("src", "fable-library-dart", "**", "*.dart")
Path.Combine("src", "fable-library-dart", "**", "*.fs")
],
Path.Combine(".", "temp", "fable-library-dart")
)

Expand Down
15 changes: 12 additions & 3 deletions src/Fable.Build/FableLibrary/Python.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,25 @@ open System.IO
open Fake.IO
open Build.Utils
open SimpleExec
open BlackFox.CommandLine

type BuildFableLibraryPython(?skipCore: bool) =
type BuildFableLibraryPython(?skipCore: bool, ?postFableBuildStage: unit -> unit) =
inherit
BuildFableLibrary(
language = "python",
libraryDir = Path.Combine("src", "fable-library-py"),
sourceDir = Path.Combine("src", "fable-library-py", "fable_library"),
buildDir = Path.Combine("temp", "fable-library-py"),
outDir = Path.Combine("temp", "fable-library-py", "fable_library")
outDir = Path.Combine("temp", "fable-library-py", "fable_library"),
inputPatterns =
[
Path.Combine("src", "fable-library-py", "**", "*.py")
Path.Combine("src", "fable-library-py", "**", "*.fs")
Path.Combine("src", "fable-library-ts", "**", "*.fs")
]
)

let skipCore = defaultArg skipCore false
let postFableBuildStage = defaultArg postFableBuildStage ignore

override this.CopyStage() =
// Copy all Python/F# files to the build directory
Expand Down Expand Up @@ -53,3 +59,6 @@ type BuildFableLibraryPython(?skipCore: bool) =
Command.Run("uv", $"run ruff check --select I,F401 --fix {this.BuildDir}")
// Run Ruff formatter on all generated files
Command.Run("uv", $"run ruff format {this.BuildDir}")

// Run the post fable buil stage if provided (used for quicktest to install the library in editable mode)
postFableBuildStage ()
8 changes: 7 additions & 1 deletion src/Fable.Build/FableLibrary/Rust.fs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ type BuildFableLibraryRust() =
Path.Combine("src", "fable-library-rust"),
Path.Combine("src", "fable-library-rust", "src"),
Path.Combine("temp", "fable-library-rust"),
Path.Combine("temp", "fable-library-rust", "src")
Path.Combine("temp", "fable-library-rust", "src"),
inputPatterns =
[
Path.Combine("src", "fable-library-rust", "**", "*.rs")
Path.Combine("src", "fable-library-rust", "**", "*.fs")
Path.Combine("src", "fable-library-rust", "Cargo.toml")
]
)

override this.PostFableBuildStage() =
Expand Down
4 changes: 4 additions & 0 deletions src/Fable.Build/FableLibrary/TypeScript.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ type BuildFableLibraryTypeScript() =
Path.Combine("src", "fable-library-ts"),
Path.Combine("temp", "fable-library-ts"),
Path.Combine("temp", "fable-library-ts"),
[
Path.Combine("src", "fable-library-ts", "**", "*.ts")
Path.Combine("src", "fable-library-ts", "**", "*.fs")
],
Path.Combine(".", "temp", "fable-library-ts")
)

Expand Down
12 changes: 6 additions & 6 deletions src/Fable.Build/Main.fs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Available commands:
beam Run for BEAM (Erlang)

Options:
--skip-fable-library Skip building fable-library if folder already exists
--force-fable-library Force building fable-library
--watch Watch for changes and re-run the tests

test Run the main tests suite
Expand All @@ -49,7 +49,7 @@ Available commands:

Options for all except integration and standalone:
--watch Watch for changes and re-run the tests
--skip-fable-library Skip building fable-library if folder already exists
--force-fable-library Force building fable-library
--no-dotnet When in watch mode, do not run the .NET tests

Options for JavaScript:
Expand All @@ -73,28 +73,28 @@ Available commands:
on top of of Node.js

Options:
--skip-fable-library Skip building fable-library if folder already exists
--force-fable-library Force building fable-library
--no-minify Don't minify the JavaScript output
--watch Watch for changes and recompile

worker-js Compile the worker for the standalone version of Fable

Options:
--skip-fable-library Skip building fable-library if folder already exists
--force-fable-library Force building fable-library
--no-minify Don't minify the JavaScript output

compiler-js Compile the Fable compiler to JavaScript

Options:
--skip-fable-library Skip building fable-library if folder already exists
--force-fable-library Force building fable-library
--no-minify Don't minify the JavaScript output

package Generate local package for Fable.Cli and Fable.Core
allowing to use this local package for testing
inside of other projects

Options:
--skip-fable-library Skip building fable-library if folder already exists
--force-fable-library Force building fable-library

publish Publish the different packages to NuGet and NPM
based on the CHANGELOG.md files
Expand Down
14 changes: 7 additions & 7 deletions src/Fable.Build/Package.fs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ open EasyBuild.Tools.PackageJson
let private packageDestination = Path.Resolve("temp", "packages")

let handle (args: string list) =
let skipFableLibrary = args |> List.contains "--skip-fable-library"
let forceFableLibrary = args |> List.contains "--force-fable-library"
// Build all the fable-libraries
BuildFableLibraryBeam().Run(skipFableLibrary)
BuildFableLibraryDart().Run(skipFableLibrary)
BuildFableLibraryJavaScript().Run(skipFableLibrary)
BuildFableLibraryPython().Run(skipFableLibrary)
BuildFableLibraryRust().Run(skipFableLibrary)
BuildFableLibraryTypeScript().Run(skipFableLibrary)
BuildFableLibraryBeam().Run(forceFableLibrary)
BuildFableLibraryDart().Run(forceFableLibrary)
BuildFableLibraryJavaScript().Run(forceFableLibrary)
BuildFableLibraryPython().Run(forceFableLibrary)
BuildFableLibraryRust().Run(forceFableLibrary)
BuildFableLibraryTypeScript().Run(forceFableLibrary)

Directory.clean packageDestination

Expand Down
18 changes: 10 additions & 8 deletions src/Fable.Build/Publish.fs
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,14 @@ let private publishNpm (projectDir: string) =

let handle (args: string list) =
// Build all the fable-libraries
BuildFableLibraryBeam().Run()
BuildFableLibraryDart().Run()
BuildFableLibraryJavaScript().Run()
BuildFableLibraryPython().Run()
BuildFableLibraryRust().Run()
BuildFableLibraryTypeScript().Run()
// Force rebuld of fable-libraries to make sure they are generated with the latest
// version of the compiler
BuildFableLibraryBeam().Run(true)
BuildFableLibraryDart().Run(true)
BuildFableLibraryJavaScript().Run(true)
BuildFableLibraryPython().Run(true)
BuildFableLibraryRust().Run(true)
BuildFableLibraryTypeScript().Run(true)

// Handle the NPM packages

Expand Down Expand Up @@ -132,8 +134,8 @@ let handle (args: string list) =
// Trigger fable-compiler-js target to make sure everything is ready for publish
// Note: fable-standalone is built as part of fable-compiler-js
// so no need to build it separately
// Note 2: We already built fable-library, so we skip it here
CompilerJs.handle [ "--skip-fable-library" ]
// Note 2: We already built fable-library, it will be skipped thanks to incremental build
CompilerJs.handle []

publishNpm ProjectDir.fable_standalone
publishNpm ProjectDir.fable_compiler_js
4 changes: 2 additions & 2 deletions src/Fable.Build/Quicktest/Core.fs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ type QuicktestConfig =
}

let genericQuicktest (config: QuicktestConfig) (args: string list) =
let skipFableLibrary = args |> List.contains "--skip-fable-library"
let forceFableLibrary = args |> List.contains "--force-fable-library"
let isWatch = args |> List.contains "--watch"

config.FableLibBuilder.Run(skipFableLibrary)
config.FableLibBuilder.Run(forceFableLibrary)

let appendRunMode (cmdLine: CmdLine) =
match config.RunMode with
Expand Down
Loading
Loading