diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml new file mode 100644 index 000000000000..10a2b5d4b826 --- /dev/null +++ b/.github/workflows/linux-build.yml @@ -0,0 +1,29 @@ +# yamllint disable rule:line-length rule:document-start rule:truthy +name: Linux Build Verification +on: + pull_request: + +permissions: + contents: read + +jobs: + linux-build: + name: Verify Linux Build + runs-on: ubuntu-latest + + steps: + - name: 'Checkout' + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: recursive + + - name: Check system dependencies + run: | + set -ex + ./system-dependencies.sh + + - name: Build on Linux + run: | + set -ex + make -j$(nproc) diff --git a/Make.config b/Make.config index 34026f4745dc..86a7f6a05e4e 100644 --- a/Make.config +++ b/Make.config @@ -1,5 +1,11 @@ include $(TOP)/mk/subdirs.mk +# Detect if we're building on Linux +UNAME_S:=$(shell uname -s) +ifeq ($(UNAME_S),Linux) +IS_LINUX=1 +endif + # Common cURL command: # --fail: return an exit code if the connection succeeded, but returned an HTTP error code. # --location: follow redirects @@ -203,6 +209,7 @@ MACCATALYST_NUGET_VERSION_FULL=$(MACCATALYST_NUGET_VERSION_NO_METADATA)$(NUGET_B # Xcode version should have both a major and a minor version (even if the minor version is 0) XCODE_VERSION=26.2 XCODE_URL=https://dl.internalx.com/internal-files/xcodes/Xcode_26.2.xip +ifndef IS_LINUX XCODE_DEVELOPER_ROOT=/Applications/Xcode_26.2.0.app/Contents/Developer XCODE_PRODUCT_BUILD_VERSION:=$(shell /usr/libexec/PlistBuddy -c 'Print :ProductBuildVersion' $(XCODE_DEVELOPER_ROOT)/../version.plist 2>/dev/null || echo " $(shell tput setaf 1 2>/dev/null)The required Xcode ($(XCODE_VERSION)) is not installed in $(basename $(basename $(XCODE_DEVELOPER_ROOT)))$(shell tput sgr0 2>/dev/null)" >&2) @@ -224,6 +231,12 @@ endif # Tell both Xcode and our build logic which Xcode we're using. export DEVELOPER_DIR=$(XCODE_DEVELOPER_ROOT) export MD_APPLE_SDK_ROOT=$(abspath $(XCODE_DEVELOPER_ROOT)/../..) +else +# On Linux, set placeholder Xcode values +XCODE_PRODUCT_BUILD_VERSION= +XCODE_IS_STABLE=true +XCODE_IS_PREVIEW=false +endif # We don't need to be told there are workload updates export DOTNET_CLI_WORKLOAD_UPDATE_NOTIFY_DISABLE=true diff --git a/Makefile b/Makefile index b50fb6017049..4de895635c0a 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,18 @@ TOP=. -SUBDIRS=builds runtime src msbuild tools +SUBDIRS=builds include $(TOP)/Make.config include $(TOP)/mk/versions.mk +# On Linux, skip directories that require native compilation or macOS platform +ifndef IS_LINUX +SUBDIRS += runtime +endif + +SUBDIRS += src msbuild tools + +ifndef IS_LINUX SUBDIRS += dotnet +endif # # Common diff --git a/builds/Makefile b/builds/Makefile index 30d12f112f01..f82a4ed63fe6 100644 --- a/builds/Makefile +++ b/builds/Makefile @@ -25,7 +25,8 @@ downloads/$(DOTNET_INSTALL_NAME): dotnet-install.sh tar -xzf $(DOTNET_CACHE_FILENAME) -C "$@.tmp"; \ else \ ./dotnet-install.sh --install-dir "$@.tmp" --version "$(DOTNET_VERSION)" --architecture $(DOTNET_ARCH) --no-path --keep-zip --zip-path "downloads/$(DOTNET_FILENAME)" $$DOTNET_INSTALL_EXTRA_ARGS; \ - cp -c downloads/$(DOTNET_FILENAME) $(DOTNET_CACHE_FILENAME); \ + mkdir -p $$(dirname $(DOTNET_CACHE_FILENAME)); \ + $(CP) downloads/$(DOTNET_FILENAME) $(DOTNET_CACHE_FILENAME); \ echo "Cached the download of $(DOTNET_FILENAME) in ~/Library/Caches/xamarin-macios"; \ fi $(Q) rm -Rf "$@" diff --git a/builds/create-csproj-for-all-packagereferences.sh b/builds/create-csproj-for-all-packagereferences.sh index 7fee50e75cab..a33d0388aa1d 100755 --- a/builds/create-csproj-for-all-packagereferences.sh +++ b/builds/create-csproj-for-all-packagereferences.sh @@ -4,6 +4,13 @@ WHITE=$(tput setaf 7 || true) RED=$(tput setaf 9 || true) CLEAR=$(tput sgr0 || true) +# Detect the OS to use the right sed syntax +if [[ "$(uname -s)" == "Darwin" ]]; then + SED_INPLACE_FLAGS=(-i '') +else + SED_INPLACE_FLAGS=(-i) +fi + OUTPUTPATH= while [[ $# -gt 0 ]]; do case $1 in @@ -35,7 +42,7 @@ while [[ $# -gt 0 ]]; do esac done -TMPPATH=$(PWD)/packagereferences.tmp.csproj +TMPPATH="$PWD/packagereferences.tmp.csproj" # Go to the root directory cd "$(git rev-parse --show-toplevel)" @@ -44,16 +51,16 @@ cd "$(git rev-parse --show-toplevel)" git grep -e '' -h > "$TMPPATH" # Replace double double quotes with a single double quote. This happens in source code that generates project files (for tests). -sed -i '' 's/""/"/g' "$TMPPATH" +sed "${SED_INPLACE_FLAGS[@]}" 's/""/"/g' "$TMPPATH" # Remove packages that we build locally -sed -i '' '/Xamarin.Tests.FrameworksInRuntimesNativeDirectory/d' "$TMPPATH" -sed -i '' '/Xamarin.Tests.DynamicLibrariesInRuntimesNativeDirectory/d' "$TMPPATH" -sed -i '' '/Xamarin.Tests.XCFrameworkWithStaticLibraryInRuntimesNativeDirectory/d' "$TMPPATH" -sed -i '' '/Xamarin.Tests.XCFrameworkWithSymlinks/d' "$TMPPATH" +sed "${SED_INPLACE_FLAGS[@]}" '/Xamarin.Tests.FrameworksInRuntimesNativeDirectory/d' "$TMPPATH" +sed "${SED_INPLACE_FLAGS[@]}" '/Xamarin.Tests.DynamicLibrariesInRuntimesNativeDirectory/d' "$TMPPATH" +sed "${SED_INPLACE_FLAGS[@]}" '/Xamarin.Tests.XCFrameworkWithStaticLibraryInRuntimesNativeDirectory/d' "$TMPPATH" +sed "${SED_INPLACE_FLAGS[@]}" '/Xamarin.Tests.XCFrameworkWithSymlinks/d' "$TMPPATH" # Get only the name and version of each package, and write that back in a PackageDownload item -sed -i '' 's@.*.*@\t\t@g' "$TMPPATH" +sed "${SED_INPLACE_FLAGS[@]}" 's@.*.*@\t\t@g' "$TMPPATH" # Sort the references and only list each once. sort -u -o "$TMPPATH" "$TMPPATH" diff --git a/create-make-config.sh b/create-make-config.sh index e5f581a73631..0bcd5739034c 100755 --- a/create-make-config.sh +++ b/create-make-config.sh @@ -14,13 +14,13 @@ export LANG # Compute commit distances for platform in $ALL_DOTNET_PLATFORMS; do PLATFORM=$(echo "$platform" | tr '[:lower:]' '[:upper:]') - COMMIT=$(git blame -- ./Make.versions HEAD | grep "${PLATFORM}_NUGET_OS_VERSION=" | sed 's/ .*//') + COMMIT=$(git blame -- ./Make.versions HEAD | grep "${PLATFORM}_NUGET_OS_VERSION=" | sed 's/ .*//' | sed 's/^\^//') COMMIT_DISTANCE=$(git log "$COMMIT..HEAD" --oneline | wc -l | sed -e 's/ //g') TOTAL_DISTANCE=$((NUGET_VERSION_COMMIT_DISTANCE_START+COMMIT_DISTANCE)) printf "${PLATFORM}_NUGET_COMMIT_DISTANCE:=$TOTAL_DISTANCE\\n" >> "$OUTPUT_FILE" done -STABLE_COMMIT=$(git blame -L '/^[#[:blank:]]*NUGET_RELEASE_BRANCH=/,+1' -- ./Make.config HEAD | sed 's/ .*//') +STABLE_COMMIT=$(git blame -L '/^[#[:blank:]]*NUGET_RELEASE_BRANCH=/,+1' -- ./Make.config HEAD | sed 's/ .*//' | sed 's/^\^//') STABLE_COMMIT_DISTANCE=$(git log "$STABLE_COMMIT..HEAD" --oneline | wc -l | sed -e 's/ //g') STABLE_TOTAL_DISTANCE=$((STABLE_COMMIT_DISTANCE+NUGET_VERSION_STABLE_COMMIT_DISTANCE_START)) diff --git a/dotnet/Makefile b/dotnet/Makefile index b8729d992617..4d438a5648b4 100644 --- a/dotnet/Makefile +++ b/dotnet/Makefile @@ -312,13 +312,13 @@ define InstallWorkload $(Q) touch $$@ $(DOTNET_SDK_MANIFESTS_PATH)/$(MACIOS_MANIFEST_VERSION_BAND)/microsoft.net.sdk.$3: .stamp-workload-replace-$1-$(DOTNET_VERSION) | $(DOTNET_SDK_MANIFESTS_PATH)/$(MACIOS_MANIFEST_VERSION_BAND) - $$(Q_LN) ln -Fhs $$(abspath Workloads/Microsoft.NET.Sdk.$1) $$(abspath $$@) + $$(Q_LN) ln -Fs $$(abspath Workloads/Microsoft.NET.Sdk.$1) $$(abspath $$@) $(DOTNET_PACKS_PATH)/$($(1)_NUGET_SDK_NAME)/$2: | $(DOTNET_PACKS_PATH)/$($(1)_NUGET_SDK_NAME) - $$(Q_LN) ln -Fhs $$(abspath $(DOTNET_DESTDIR)/$($(1)_NUGET_SDK_NAME)) $$(abspath $$@) + $$(Q_LN) ln -Fs $$(abspath $(DOTNET_DESTDIR)/$($(1)_NUGET_SDK_NAME)) $$(abspath $$@) $(DOTNET_PACKS_PATH)/$($(1)_NUGET_REF_NAME)/$2: | $(DOTNET_PACKS_PATH)/$($(1)_NUGET_REF_NAME) - $$(Q_LN) ln -Fhs $$(abspath $(DOTNET_DESTDIR)/$($(1)_NUGET_REF_NAME)) $$(abspath $$@) + $$(Q_LN) ln -Fs $$(abspath $(DOTNET_DESTDIR)/$($(1)_NUGET_REF_NAME)) $$(abspath $$@) $(DOTNET_TEMPLATE_PACKS_PATH)/Microsoft.$1.Templates.$(2).nupkg: $(TEMPLATE_PACKS_$(shell echo $(1) | tr a-z A-Z)) | $(DOTNET_TEMPLATE_PACKS_PATH) $$(Q) $$(CP) $$< $$@ @@ -333,7 +333,7 @@ $(foreach platform,$(DOTNET_PLATFORMS),$(eval $(call InstallWorkload,$(platform) define InstallRuntimeManagedWorkload $(DOTNET_PACKS_PATH)/$$($(1)_NUGET_RUNTIME_MANAGED_NAME)/$2: | $(DOTNET_PACKS_PATH)/$$($(1)_NUGET_RUNTIME_MANAGED_NAME) - $$(Q_LN) ln -Fhs $$(abspath $(DOTNET_DESTDIR)/$$($(1)_NUGET_RUNTIME_MANAGED_NAME)) $$(abspath $$@) + $$(Q_LN) ln -Fs $$(abspath $(DOTNET_DESTDIR)/$$($(1)_NUGET_RUNTIME_MANAGED_NAME)) $$(abspath $$@) WORKLOAD_TARGETS += \ $(DOTNET_PACKS_PATH)/$$($(1)_NUGET_RUNTIME_MANAGED_NAME)/$2 @@ -342,7 +342,7 @@ $(foreach platform,$(DOTNET_PLATFORMS),$(eval $(call InstallRuntimeManagedWorklo define InstallRuntimeWorkload $(DOTNET_PACKS_PATH)/$$($(2)_NUGET_RUNTIME_NAME)/$3: | $(DOTNET_PACKS_PATH)/$$($(2)_NUGET_RUNTIME_NAME) - $$(Q_LN) ln -Fhs $$(abspath $(DOTNET_DESTDIR)/$$($(2)_NUGET_RUNTIME_NAME)) $$(abspath $$@) + $$(Q_LN) ln -Fs $$(abspath $(DOTNET_DESTDIR)/$$($(2)_NUGET_RUNTIME_NAME)) $$(abspath $$@) WORKLOAD_TARGETS += \ $(DOTNET_PACKS_PATH)/$$($(2)_NUGET_RUNTIME_NAME)/$3 diff --git a/msbuild/Makefile b/msbuild/Makefile index e91a7e09dabd..c7dc8d9e0059 100644 --- a/msbuild/Makefile +++ b/msbuild/Makefile @@ -115,15 +115,20 @@ DOTNET_IOS_WINDOWS_FILES += Messaging/Xamarin.Messaging.Build/obj/$(CONFIG)/Buil .dotnet-windows: .build-stamp .copy-windows-files +ifndef IS_LINUX all-local:: .dotnet-windows dotnet:: .dotnet-windows +endif ## ## Common targets ## ## # we must install locally during 'make all', because the F# build depends on the msbuild targets/assemblies. -all-local:: $(MSBUILD_PRODUCTS) .stamp-test-xml +all-local:: $(MSBUILD_PRODUCTS) +ifndef IS_LINUX +all-local:: .stamp-test-xml +endif # I haven't found a way to execute ilrepack.exe on .NET (it will probably have to be built for .NET), so run it using Mono. diff --git a/src/ILLink.Substitutions.ios.xml b/src/ILLink.Substitutions.iOS.xml similarity index 100% rename from src/ILLink.Substitutions.ios.xml rename to src/ILLink.Substitutions.iOS.xml diff --git a/src/ILLink.Substitutions.tvos.xml b/src/ILLink.Substitutions.tvOS.xml similarity index 100% rename from src/ILLink.Substitutions.tvos.xml rename to src/ILLink.Substitutions.tvOS.xml diff --git a/src/Makefile b/src/Makefile index 9ac7b1c03218..8fb8a3f67808 100644 --- a/src/Makefile +++ b/src/Makefile @@ -346,13 +346,21 @@ $(DOTNET_DESTDIR)/$($(2)_NUGET_REF_NAME)/ref/$(DOTNET_TFM)/Microsoft.$(1).dll: $ $(DOTNET_DESTDIR)/$($(2)_NUGET_REF_NAME)/ref/$(DOTNET_TFM)/Microsoft.$(1).xml: $($(2)_DOTNET_BUILD_DIR)/doc/Microsoft.$(1).xml | $(DOTNET_DESTDIR)/$($(2)_NUGET_REF_NAME)/ref/$(DOTNET_TFM) $$(Q) $(CP) $$< $$@ +ifndef IS_LINUX $($(2)_DOTNET_BUILD_DIR)/doc/Microsoft.$(1).xml: $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).xml $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).dll build/.build-adr-stamp | $($(2)_DOTNET_BUILD_DIR)/doc $$(Q_GEN) $(TOP)/packages/appledocreader.$(ADR_RUNTIME_IDENTIFIER)/$(ADR_NUGET_VERSION)/tools/any/$(ADR_RUNTIME_IDENTIFIER)/AppleDocReader inject docs --assembly="$(abspath $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).dll)" --input="$(abspath $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).xml)" --output="$(abspath $$@)" --xcode="$(DEVELOPER_DIR)/../.." --runtimeDll="$(DOTNET_BCL_DIR)/System.Runtime.dll" -f +else +# On Linux, skip AppleDocReader (macOS-only tool) and just copy the XML +$($(2)_DOTNET_BUILD_DIR)/doc/Microsoft.$(1).xml: $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).xml | $($(2)_DOTNET_BUILD_DIR)/doc + $(Q) $(CP) $$< $$@ +endif endef +ifndef IS_LINUX build/.build-adr-stamp: $(MAKE) -C $(TOP)/tools/adr $(Q) touch $@ +endif # Template variables: # 1: Platform (correct case) diff --git a/src/Makefile.generator b/src/Makefile.generator index 339ee1e79870..059b977890f1 100644 --- a/src/Makefile.generator +++ b/src/Makefile.generator @@ -71,6 +71,6 @@ $(RSP_DIR)/dotnet/%-defines-dotnet.rsp: frameworks.sources Makefile.generator $( $(Q) $(GENERATE_DEFINES_EXEC) $@.tmp '$(filter-out $(DOTNET_REMOVED_$(shell echo $* | tr a-z A-Z)_FRAMEWORKS),$($(shell echo $* | tr a-z A-Z)_FRAMEWORKS))' $(Q) mv $@.tmp $@ -$(DOTNET_BUILD_DIR)/Xamarin.Apple.BindingAttributes.dll: bgen/Attributes.cs bgen/PlatformName.cs bgen/DotnetGlobals.cs Makefile.generator | $(DOTNET_BUILD_DIR) - $(Q_DOTNET_BUILD) $(DOTNET_CSC) $(DOTNET_FLAGS) -d:BINDING_ATTRIBUTES_DLL -out:$@ bgen/Attributes.cs bgen/PlatformName.cs bgen/DotnetGlobals.cs +$(DOTNET_BUILD_DIR)/Xamarin.Apple.BindingAttributes.dll: bgen/Attributes.cs bgen/PlatformName.cs bgen/DotNetGlobals.cs Makefile.generator | $(DOTNET_BUILD_DIR) + $(Q_DOTNET_BUILD) $(DOTNET_CSC) $(DOTNET_FLAGS) -d:BINDING_ATTRIBUTES_DLL -out:$@ bgen/Attributes.cs bgen/PlatformName.cs bgen/DotNetGlobals.cs diff --git a/src/quicklookUI.cs b/src/quicklookui.cs similarity index 100% rename from src/quicklookUI.cs rename to src/quicklookui.cs diff --git a/system-dependencies.sh b/system-dependencies.sh index c57ca03a52b2..fbf8a318718e 100755 --- a/system-dependencies.sh +++ b/system-dependencies.sh @@ -4,6 +4,27 @@ set -o pipefail cd $(dirname $0) +# Detect if we're running on Linux +if [[ "$(uname -s)" == "Linux" ]]; then + IS_LINUX=1 + # On Linux, ignore all macOS-specific dependencies + IGNORE_OSX=1 + IGNORE_XCODE=1 + IGNORE_XCODE_COMPONENTS=1 + IGNORE_MONO=1 + IGNORE_VISUAL_STUDIO=1 + IGNORE_SHARPIE=1 + IGNORE_SIMULATORS=1 + IGNORE_OLD_SIMULATORS=1 + IGNORE_7Z=1 + IGNORE_HOMEBREW=1 + IGNORE_SHELLCHECK=1 + IGNORE_YAMLLINT=1 + IGNORE_PYTHON3=1 +else + IS_LINUX= +fi + FAIL= PROVISION_DOWNLOAD_DIR=/tmp/x-provisioning SUDO=sudo @@ -924,6 +945,11 @@ function check_osx_version () { } function check_checkout_dir () { + # Skip on Linux - this check is macOS-specific + if test -n "$IS_LINUX"; then + return + fi + # use apple script to get the possibly translated special folders and check that we are not a subdir for special in documents downloads desktop; do path=$(osascript -e "set result to POSIX path of (path to $special folder as string)") @@ -1116,6 +1142,11 @@ function check_old_simulators () echo "Checking system..." +if test -n "$IS_LINUX"; then + ok "Running on ${COLOR_BLUE}Linux${COLOR_CLEAR} - skipping macOS-specific checks" + ok "Only .NET download and managed code builds will be available" +fi + check_osx_version check_checkout_dir check_xcode diff --git a/tests/Makefile b/tests/Makefile index e264319f92a6..1b9d8451c0e1 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,7 +1,13 @@ TOP = .. -SUBDIRS=test-libraries dotnet include $(TOP)/Make.config + +# Skip test-libraries on Linux (requires native compilation with Xcode/clang) +ifndef IS_LINUX +SUBDIRS=test-libraries +endif + +SUBDIRS += dotnet include $(TOP)/mk/rules.mk XHARNESS_EXECUTABLE=xharness/bin/Debug/xharness.dll diff --git a/tools/common/create-makefile-fragment.sh b/tools/common/create-makefile-fragment.sh index 3b86f5b57491..70ecf077e50f 100755 --- a/tools/common/create-makefile-fragment.sh +++ b/tools/common/create-makefile-fragment.sh @@ -15,6 +15,13 @@ cd "$(dirname "$0")" +# Detect OS for sed syntax +if [[ "$OSTYPE" == "darwin"* ]]; then + SED_INPLACE_FLAGS=(-i '') +else + SED_INPLACE_FLAGS=(-i) +fi + if test -z "$1"; then echo "Must specify the project file to process." exit 1 @@ -104,12 +111,12 @@ for proj in $(sort "$REFERENCES_PATH" | uniq); do # The output contains relative paths, relative to the csproj directory # Change those to full paths by prepending the csproj directory. - sed -i '' "s@^@$proj_dir/@" "$inputs_path" + sed "${SED_INPLACE_FLAGS[@]}" "s@^@$proj_dir/@" "$inputs_path" # Change to Make syntax. This is horrifically difficult in MSBuild, # because MSBuild blindly replaces backslashes with forward slashes (i.e. # windows paths to unix paths...) - sed -i '' "s_^\\(.*\\)\$_ \\1 \\\\_" "$inputs_path" + sed "${SED_INPLACE_FLAGS[@]}" "s_^\\(.*\\)\$_ \\1 \\\\_" "$inputs_path" # Clean up rm -f "$TMPPROJ" @@ -125,7 +132,7 @@ sort "${INPUT_PATHS[@]}" | uniq >> "$FRAGMENT_PATH" # Simplify paths somewhat by removing the current directory if test -z "$ABSOLUTE_PATHS"; then - sed -i '' "s@$PROJECT_DIR/@@" "$FRAGMENT_PATH" + sed "${SED_INPLACE_FLAGS[@]}" "s@$PROJECT_DIR/@@" "$FRAGMENT_PATH" fi # Cleanup diff --git a/tools/dotnet-linker/Makefile b/tools/dotnet-linker/Makefile index 74f0da344f60..d414b2a5f9ba 100644 --- a/tools/dotnet-linker/Makefile +++ b/tools/dotnet-linker/Makefile @@ -2,6 +2,7 @@ TOP=../.. include $(TOP)/Make.config include $(TOP)/mk/rules.mk +include ../common/Make.common BUILD_DIR=bin/Debug diff --git a/tools/mtouch/Makefile b/tools/mtouch/Makefile index 833bd74e0a2b..703caf79aa36 100644 --- a/tools/mtouch/Makefile +++ b/tools/mtouch/Makefile @@ -87,9 +87,11 @@ endef $(foreach platform,$(DOTNET_PLATFORMS_MTOUCH),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(eval $(call InstallRegistrar,$(platform),$(rid))))) +ifndef IS_LINUX dotnet: $(TARGETS_DOTNET) install-local:: $(TARGETS_DOTNET) all-local:: $(TARGETS_DOTNET) +endif clean-local:: rm -Rf bin obj