From e27b8c3f6f9507117f2f0ffc2c28a4c54fe03c59 Mon Sep 17 00:00:00 2001 From: Jason Naylor Date: Fri, 28 Aug 2026 12:10:26 -0700 Subject: [PATCH 1/2] Remove obsolete MSBuild wrapper scripts in favor of dotnet build build.cmd, build.sh and build/LCM.proj wrapped MSBuild against LCM.sln. CI has used dotnet build/test/pack directly for some time and nothing else in the repo referenced these files, so they only offered a second, diverging way to build. README.md and AGENTS.md now name dotnet build instead. Drop the premature Wrapper.Init() call in InitializeIcuAttribute. It ran before PATH held the lib directories and before ICU_DATA was set, so the first native ICU load had nothing to find and the environment had to be set by hand. CustomIcu.InitIcuDataDir, called a few lines later, does both. The catch message named Wrapper.Init() while guarding InitIcuDataDir; corrected. Relax global.json from rollForward latestFeature to latestMajor. The 8.0.100 pin refuses any newer SDK, blocking work on machines with no 8.0.x SDK installed. CI installs 8.0.x explicitly via setup-dotnet, so the pin was redundant there. Verified: solution builds clean on SDK 10.0.201, and previously on 9.0.316. SIL.LCModel.Core.Tests 792/792, SIL.LCModel.FixData.Tests 21/21 and SIL.LCModel.Tests 1716/1716 pass on net462 and net8.0, with ICU_DATA unset, no ICU entries on PATH, no Software\SIL\Icu70DataDir registry value and no %ProgramData%\SIL\Icu70 directory. Co-Authored-By: Claude Opus 5 (1M context) --- AGENTS.md | 12 +- README.md | 10 +- build.cmd | 20 ---- build.sh | 22 ---- build/LCM.proj | 109 ------------------ global.json | 2 +- .../Attributes/InitializeIcuAttribute.cs | 12 +- 7 files changed, 9 insertions(+), 178 deletions(-) delete mode 100644 build.cmd delete mode 100755 build.sh delete mode 100644 build/LCM.proj diff --git a/AGENTS.md b/AGENTS.md index b32e91b86..aad66aad9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -25,11 +25,6 @@ CI runs on Windows and Ubuntu. See .github/workflows/ci-cd.yml: Always mirror this sequence when validating a change locally. -### Local build scripts (not validated here) -- Windows: build.cmd [Debug|Release] [Target] (uses MSBuild on LCM.sln). -- Linux: build.sh [Debug|Release] [Target] (sources environ, uses msbuild on LCM.sln). -These scripts call build/LCM.proj targets (Build/Test/Pack). If you use them, always run from repo root. - ### Tests per README (not validated here) - Windows, ReSharper: open LCM.sln and “Run Unit Tests”. - Windows, no ReSharper: use MSBuild, then run nunit3-console.exe from artifacts/Debug/net462. @@ -53,8 +48,6 @@ No command timeouts were observed. ### Key solution and build files - LCM.sln: solution entry point. -- build.cmd / build.sh: wrapper scripts for MSBuild. -- build/LCM.proj: orchestrated build/test/pack, uses NUnit console on output/ for legacy builds. - Directory.Build.props / Directory.Build.targets: repo-wide build settings and packaging. - Directory.Solution.props / Directory.Solution.targets: solution-level defaults. - GitVersion.yml: GitVersion configuration. @@ -94,8 +87,6 @@ Code generation targets to know about: - .editorconfig - .gitattributes - .gitignore -- build.cmd -- build.sh - CHANGELOG.md - Directory.Build.props - Directory.Build.targets @@ -113,13 +104,12 @@ Code generation targets to know about: - .github/ (GitHub Actions workflow) - .vscode/ (VS settings) - artifacts/ (build outputs) -- build/ (LCM.proj) - src/ (production code) - tests/ (unit tests) ## README highlights (summary) - Describes liblcm as FieldWorks model library for linguistic analyses. -- Build: use build.cmd (Windows) or build.sh (Linux). Default Debug, optional Release. +- Build: use `dotnet build`. Default Debug, optional Release. - Debugging: use LOCAL_NUGET_REPO to publish local packages; see NuGet local feeds. - Tests: Windows via ReSharper or NUnit console; Linux via mono + NUnit console (requires environ). diff --git a/README.md b/README.md index 6419b977a..6d5d1fe41 100644 --- a/README.md +++ b/README.md @@ -26,18 +26,18 @@ with language and culture data, including anthropological, text corpus, and ling On Windows: - - Run the appropriate `vsvars*.bat`. Alternatively, `LCM.sln` can be built from within Visual Studio. - - Run `build.cmd` to build the liblcm library. + - Run `dotnet build` to build the liblcm library. Alternatively, `LCM.sln` can be built + from within Visual Studio. On Linux: - - Run `build.sh` to build the liblcm library. + - Source `environ`, then run `dotnet build` to build the liblcm library. By default, this will build liblcm in the Debug configuration. To build with a different configuration, use: ```bash -build.(cmd|sh) (Debug|Release) +dotnet build --configuration (Debug|Release) ``` ## Debugging @@ -51,7 +51,7 @@ To publish and consume LCModel through local sources: local network) to publish locally-built packages - See [these instructions](https://docs.microsoft.com/en-us/nuget/hosting-packages/local-feeds) to enable local package sources -- `build /t:pack` will pack nuget packages and publish them to `LOCAL_NUGET_REPO` +- `dotnet pack` will pack nuget packages and publish them to `LOCAL_NUGET_REPO` ## Tests diff --git a/build.cmd b/build.cmd deleted file mode 100644 index 73e1c825f..000000000 --- a/build.cmd +++ /dev/null @@ -1,20 +0,0 @@ - @ECHO OFF - -if "%1"=="" ( - SET CONFIG=Debug -) else ( - SET CONFIG=%1 -) - -if "%2"=="" ( - SET TARGET=Build -) else ( - SET TARGET=%2 -) - -if not "%3"=="" ( - echo Usage: "build [(Debug|Release) []]" - exit /b 1 -) - -msbuild /t:%TARGET% /p:Configuration=%CONFIG% LCM.sln \ No newline at end of file diff --git a/build.sh b/build.sh deleted file mode 100755 index 5a71c493d..000000000 --- a/build.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -cd "$(dirname "$0")" -if [ -z "$1" ] ; then - CONFIG=Debug -else - CONFIG=$1 -fi - -if [ -z "$2" ] ; then - TARGET=Build -else - TARGET=$2 -fi - -if [ -n "$3" ] ; then - echo Usage: "build [(Debug|Release) []]" - exit 1 -fi - -. environ -msbuild /t:$TARGET /p:Configuration=$CONFIG LCM.sln \ No newline at end of file diff --git a/build/LCM.proj b/build/LCM.proj deleted file mode 100644 index 40a27688a..000000000 --- a/build/LCM.proj +++ /dev/null @@ -1,109 +0,0 @@ - - - $(MSBuildProjectDirectory)/.. - $(teamcity_build_checkoutDir) - LCM.sln - $(RootDir)/$(Solution) - Release - KnownMonoIssue, - SkipOnTeamCity,$(ExtraExcludeCategories) - true - false - Any CPU - true - false - true - false - true - false - $(RootDir)/output/$(Configuration)/TestResults.xml - $(ContinuousIntegrationBuild) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/global.json b/global.json index 47ebafe5a..1895e98c2 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { "version": "8.0.100", - "rollForward": "latestFeature" + "rollForward": "latestMajor" } } diff --git a/tests/SIL.LCModel.Core.Tests/Attributes/InitializeIcuAttribute.cs b/tests/SIL.LCModel.Core.Tests/Attributes/InitializeIcuAttribute.cs index 615c51a95..c22766483 100644 --- a/tests/SIL.LCModel.Core.Tests/Attributes/InitializeIcuAttribute.cs +++ b/tests/SIL.LCModel.Core.Tests/Attributes/InitializeIcuAttribute.cs @@ -37,15 +37,7 @@ public override void BeforeTest(ITest testDetails) if (IcuVersion > 0) Wrapper.ConfineIcuVersions(IcuVersion); - try - { - Wrapper.Init(); - } - catch (Exception e) - { - Console.WriteLine($"InitializeIcuAttribute: ERROR: failed when calling Wrapper.Init() with {e.GetType()}: {e.Message}"); - } - + // ICU_DATA has to be resolved before InitIcuDataDir hands the data directory to ICU. EnsureIcuDataEnvironmentVariableIsSet(); try @@ -54,7 +46,7 @@ public override void BeforeTest(ITest testDetails) } catch (Exception e) { - Console.WriteLine($"InitializeIcuAttribute: ERROR: failed with {e.GetType()}: {e.Message}"); + Console.WriteLine($"InitializeIcuAttribute: ERROR: failed when calling InitIcuDataDir() with {e.GetType()}: {e.Message}"); } } From af8c5c952330e8238501c976591f089fe9c0984e Mon Sep 17 00:00:00 2001 From: Jason Naylor Date: Fri, 28 Aug 2026 13:51:06 -0700 Subject: [PATCH 2/2] Document -m:1 for cold-start builds The removed wrapper scripts called msbuild without /m, so they were implicitly serial. dotnet build is parallel by default, and on a tree with no generated sources yet the GenerateModel and GenerateKernelCs targets can run concurrently against the same non-per-framework outputs, then fail as LcmGenerate or IdlImp "returned false but did not log an error". The failure is intermittent, so the error is easy to misread as a broken change. README.md and AGENTS.md now name -m:1 for a cold-start build. Correct the Windows prerequisite to Visual Studio 2022. net8.0 targets were added in #385 and VS 2019 cannot build them. The C++ build tools are needed for any Windows build rather than only for building in the IDE, because code generation preprocesses the IDL with cl.exe. Drop the AGENTS.md root-file inventory, which duplicated the repository root and went stale with this change, and ask anyone whose run contradicts the file to report it. Co-Authored-By: Claude Opus 5 (1M context) --- AGENTS.md | 24 +++++------------------- README.md | 17 ++++++++++++----- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index aad66aad9..73dbdb3b2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -25,6 +25,10 @@ CI runs on Windows and Ubuntu. See .github/workflows/ci-cd.yml: Always mirror this sequence when validating a change locally. +Use `dotnet build -m:1` for a cold-start build (a tree with no generated sources yet). +Parallel builds race on the generated sources and fail with `LcmGenerate` or `IdlImp` +errors. Plain `dotnet build` is fine once those sources exist. + ### Tests per README (not validated here) - Windows, ReSharper: open LCM.sln and “Run Unit Tests”. - Windows, no ReSharper: use MSBuild, then run nunit3-console.exe from artifacts/Debug/net462. @@ -35,8 +39,6 @@ Always mirror this sequence when validating a change locally. - dotnet build --configuration Release → FAILED Failure signature (both commands): GitVersion.MsBuild (netcoreapp3.1 gitversion.dll) exited with code 1. This blocks build/test in this environment. CI uses fetch-depth 0, so ensure a full git history is available. If GitVersion still fails, check GitVersion prerequisites and local .NET runtime compatibility. -No command timeouts were observed. - ### Known prerequisites and gotchas - GitVersion.MsBuild is used across projects; it requires git metadata. CI checks out with fetch-depth 0. - net462 builds on Windows require the .NET Framework 4.6.1 targeting pack (CI installs it). @@ -83,23 +85,6 @@ Code generation targets to know about: - Mono on Linux for some runtime/test workflows. - GitVersion.MsBuild for versioning (requires git metadata). -## Root files list -- .editorconfig -- .gitattributes -- .gitignore -- CHANGELOG.md -- Directory.Build.props -- Directory.Build.targets -- Directory.Solution.props -- Directory.Solution.targets -- environ -- GitVersion.yml -- global.json -- LCM.sln -- LCM.sln.DotSettings -- LICENSE -- README.md - ## Repo top-level directories - .github/ (GitHub Actions workflow) - .vscode/ (VS settings) @@ -115,3 +100,4 @@ Code generation targets to know about: ## Trust these instructions Follow this file first. Only search the repo if these instructions are incomplete or prove incorrect for your task. +If these instructions fail notify the author of the task that they should verify and update the instructions if necessary. diff --git a/README.md b/README.md index 6d5d1fe41..2257a2e61 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,10 @@ with language and culture data, including anthropological, text corpus, and ling 1. Install Required Software - git - - Visual Studio 2019 (with C++), MonoDevelop, or JetBrains Rider + - On Windows, Visual Studio 2022 with the "Desktop development with C++" workload. + The C++ build tools are required for any Windows build, not only for building + inside the IDE: code generation preprocesses the IDL with `cl.exe`. + - JetBrains Rider or MonoDevelop, if you prefer another IDE 2. Clone the liblcm repository @@ -26,18 +29,22 @@ with language and culture data, including anthropological, text corpus, and ling On Windows: - - Run `dotnet build` to build the liblcm library. Alternatively, `LCM.sln` can be built - from within Visual Studio. + - Run `dotnet build -m:1` to build the liblcm library. Alternatively, `LCM.sln` can be + built from within Visual Studio. On Linux: - - Source `environ`, then run `dotnet build` to build the liblcm library. + - Source `environ`, then run `dotnet build -m:1` to build the liblcm library. + +Use `-m:1` for a cold-start build (a fresh clone or worktree, with no generated sources +yet). Parallel builds race on the generated sources. Plain `dotnet build` is fine once +those sources exist. By default, this will build liblcm in the Debug configuration. To build with a different configuration, use: ```bash -dotnet build --configuration (Debug|Release) +dotnet build -m:1 --configuration (Debug|Release) ``` ## Debugging