Within a macOS app, I can tell if it is #TargetDesktop or #TargetWeb. Plus I can tell if it is running as ARM with SystemInformationMBS.isARM or Intel on ARM with SystemInformationMBS.IsTranslated.
If you want to store an information in the App how you have built it, then you could use a PreBuild Script along this way:
Dim sBuildTarget As String = Str(CurrentBuildTarget)
if (ConstantValue("modAppConstants.constBuildTarget") <> sBuildTarget) then
ConstantValue("modAppConstants.constBuildTarget") = sBuildTarget
end if
This will set the value of the Constant constBuildTarget in modAppConstants.
So in your code you can e.g.:
// App Build is...
select case modAppConstants.constBuildTarget
case 9
return "macOS Universal"
case 16
return "macOS Intel"
case 24
return "macOS ARM"
end select
// Running as...
#if TargetX86 then
return "X86 (Intel)"
#elseif TargetARM then
return "ARM"
#endif
Just to be clear, there is no such thing as “running as universal”. A universal binary contains both ARM and Intel portions. Only Intel works on Intel machines. ARM works natively on Apple Silicon machines and Intel runs under Rosetta 2.
I’m writing a generic updater app for the MBS conference. It will allow you to keep macOS users as Intel-only, ARM-only or Universal in regards the new app version they download. Of course Universal is easier, but eventually we may all go ARM-only. I just want to give users the flexibility now.
Similarly, you can keep Window and Linux 32-bit users on their own specific versions.
I think the Build XojoScript might be the only way to go, unless someone has a different solution.
I built my test app as Intel-only, ARM-only and Universal, and they were identical file for file, except the Contents>MacOS>AppName executable file size.
The more important thing is to avoid installing a future ARM only app on an Intel Mac. That would break it. And avoid installing a newer version on an older macOS version where it doesn’t run there.
This is precisely why I want to be able to allow the user to choose a CPU lane and keep to their lane, and not upgrade Intel Macs/PCs to ARM versions, or 32-bit versions to 64-bit, or keep Universal apps around for too many years.
For future reference, here is a Method that works:
Protected Function isMacOSUniversalBuild() As Boolean
'forum.xojo.com/t/how-to-tell-if-app-is-running-as-macos-app-universal/87387/14
#If TargetMacOS Then
Var f As FolderItem = App.ExecutableFile
If f = Nil Or Not f.Exists Then
Return False
End If
'For macOS the executable starts With
'CF FA ED FE 0C 00 00 01 for ARM
'CF FA ED FE 07 00 00 01 for Intel
'CA FE BA BE 00 00 00 02 for Universal
Var AppString As String = CommonFolders.getFileToString(f, True).Left(8)
If AppString.MiddleBytes(0, 1).AscByte.ToHex = "CA" And _
AppString.MiddleBytes(1, 1).AscByte.ToHex = "FE" And _
AppString.MiddleBytes(2, 1).AscByte.ToHex = "BA" And _
AppString.MiddleBytes(3, 1).AscByte.ToHex = "BE" And _
AppString.MiddleBytes(4, 1).AscByte.ToHex = "0" And _
AppString.MiddleBytes(5, 1).AscByte.ToHex = "0" And _
AppString.MiddleBytes(6, 1).AscByte.ToHex = "0" And _
AppString.MiddleBytes(7, 1).AscByte.ToHex = "2" Then
Return True 'Universal
ElseIf AppString.MiddleBytes(0, 1).AscByte.ToHex = "CF" And _
AppString.MiddleBytes(1, 1).AscByte.ToHex = "FA" And _
AppString.MiddleBytes(2, 1).AscByte.ToHex = "ED" And _
AppString.MiddleBytes(3, 1).AscByte.ToHex = "FE" And _
AppString.MiddleBytes(4, 1).AscByte.ToHex = "C" And _
AppString.MiddleBytes(5, 1).AscByte.ToHex = "0" And _
AppString.MiddleBytes(6, 1).AscByte.ToHex = "0" And _
AppString.MiddleBytes(7, 1).AscByte.ToHex = "1" Then
Return False 'ARM only
ElseIf AppString.MiddleBytes(0, 1).AscByte.ToHex = "CF" And _
AppString.MiddleBytes(1, 1).AscByte.ToHex = "FA" And _
AppString.MiddleBytes(2, 1).AscByte.ToHex = "ED" And _
AppString.MiddleBytes(3, 1).AscByte.ToHex = "FE" And _
AppString.MiddleBytes(4, 1).AscByte.ToHex = "7" And _
AppString.MiddleBytes(5, 1).AscByte.ToHex = "0" And _
AppString.MiddleBytes(6, 1).AscByte.ToHex = "0" And _
AppString.MiddleBytes(7, 1).AscByte.ToHex = "1" Then
Return False 'Intel only
'Else
'MessageBox "I don't know what app CPU I am: " + AppString.MiddleBytes(0, 1).AscByte.ToHex + "," +AppString.MiddleBytes(1, 1).AscByte.ToHex + "," +AppString.MiddleBytes(2, 1).AscByte.ToHex + "," +AppString.MiddleBytes(3, 1).AscByte.ToHex + "," +AppString.MiddleBytes(4, 1).AscByte.ToHex + "," +AppString.MiddleBytes(5, 1).AscByte.ToHex + "," +AppString.MiddleBytes(6, 1).AscByte.ToHex + "," +AppString.MiddleBytes(7, 1).AscByte.ToHex
End If
#EndIf
Return False
End Function
Since the tag is 8 bytes, we can improve the code. Rather than reading the entire App executable into a string (which may be 100s of MB) we just read the first 8 bytes:
Public Function MacOSUniversialBuildType() As String
var f as FolderItem = app.ExecutableFile
var bs as BinaryStream = BinaryStream.Open(f)
var tag as integer = bs.ReadUInt64
var tagHex as string = tag.ToHex
select case tagHex
case "CAFEBABE00000002"
return "Universal"
case "CFFAEDFE07000001"
return "Intel"
case "CFFAEDFE0C000001"
return "ARM"
else
return "Unknown"
end select
End Function