@@ -350,6 +350,7 @@ extern (C++) struct Target
350350
351351 OS os;
352352 ubyte osMajor;
353+ uint osVersionLong; // / major, minor, patch version for getTargetInfo.
353354
354355 // D ABI
355356 ubyte ptrsize; // / size of a pointer in bytes
@@ -1275,14 +1276,17 @@ extern (C++) struct Target
12751276 }
12761277 }
12771278
1278- // this guarantees `getTargetInfo` and `allTargetInfos` remain in sync
1279+ // NOTE: If `allTargetInfos` gets implemented, the platform-specific keys
1280+ // should be moved to a separate enum.
12791281 private enum TargetInfoKeys
12801282 {
12811283 cppRuntimeLibrary,
12821284 cppStd,
12831285 floatAbi,
12841286 objectFormat,
1285- CET
1287+ CET ,
1288+ OSXVersion,
1289+ FreeBSDVersion,
12861290 }
12871291
12881292 /**
@@ -1303,6 +1307,11 @@ extern (C++) struct Target
13031307 {
13041308 return new StringExp(loc, sval);
13051309 }
1310+ IntegerExp osVersion (uint v)
1311+ {
1312+ osVersionLong = v;
1313+ return new IntegerExp(v);
1314+ }
13061315
13071316 switch (name.toDString) with (TargetInfoKeys)
13081317 {
@@ -1323,6 +1332,83 @@ extern (C++) struct Target
13231332 case CET .stringof:
13241333 return new IntegerExp(driverParams.ibt);
13251334
1335+ case OSXVersion.stringof:
1336+ if (os == Target.OS .OSX )
1337+ {
1338+ // Format of the version: XX_YY_ZZ
1339+ if (osVersionLong)
1340+ return new IntegerExp(osVersionLong);
1341+
1342+ static uint macOSVersion (uint darwin)
1343+ {
1344+ // Old darwin kernel versions 4 to 19 map to macOS 10.0 to 10.15
1345+ if (darwin >= 4 && darwin <= 13 )
1346+ return 10_00_00 + ((darwin - 4 ) * 10_00);
1347+ else if (darwin >= 14 && darwin <= 19 )
1348+ return 10_00_00 + ((darwin - 4 ) * 1_00);
1349+ // New darwin kernel versions 20 onwards map to macOS 11, 12, ...
1350+ else if (darwin >= 20 )
1351+ return ((darwin - 9 ) * 1_00_00);
1352+ return 0 ;
1353+ }
1354+ // Infer from -target= os version (i.e: darwin20)
1355+ if (auto macVersion = macOSVersion(osMajor))
1356+ return osVersion (macVersion);
1357+ // Infer from the running system.
1358+ version (OSX )
1359+ {
1360+ char [32 ] buf = 0 ;
1361+ size_t length = buf.length;
1362+ uint major, minor, tiny;
1363+ if (sysctlbyname(" kern.osproductversion" , buf.ptr, &length, null , 0 ) == 0 )
1364+ {
1365+ // Returns the macOS version string, e.g: 12.6.0
1366+ if (sscanf(buf.ptr, " %u.%u.%u" , &major, &minor, &tiny) >= 0 )
1367+ return osVersion ((major * 1_00_00) + (minor * 1_00) + tiny);
1368+ }
1369+ if (sysctlbyname(" kern.osrelease" , buf.ptr, &length, null , 0 ) == 0 )
1370+ {
1371+ // Returns the darwin version string, map to macOS.
1372+ if (sscanf(buf.ptr, " %u.%u.%u" , &major, &minor, &tiny) >= 0 )
1373+ {
1374+ if (auto macVersion = macOSVersion(major))
1375+ return osVersion (macVersion);
1376+ }
1377+ }
1378+ }
1379+ // Fallback on guessing appropriate minimum version.
1380+ if (isAArch64)
1381+ return osVersion (11_00_00);
1382+ else if (isX86_64)
1383+ return osVersion (10_06_00);
1384+ else
1385+ return osVersion (10_05_00);
1386+ }
1387+ goto default ;
1388+
1389+ case FreeBSDVersion.stringof:
1390+ if (os == Target.OS .FreeBSD)
1391+ {
1392+ // Format of the version: XX_YY_ZZZ
1393+ if (osVersionLong)
1394+ return new IntegerExp(osVersionLong);
1395+
1396+ // Infer from -target= os version (i.e: freebsd13)
1397+ if (osMajor)
1398+ return osVersion (osMajor * 1_00_000);
1399+ // Infer from the running system.
1400+ version (FreeBSD )
1401+ {
1402+ int osreldate;
1403+ size_t length = int .sizeof;
1404+ if (sysctlbyname(" kern.osreldate" , &osreldate, &length, null , 0 ) == 0 )
1405+ return osVersion (osreldate);
1406+ }
1407+ // Fallback to minimum supported version.
1408+ return osVersion (10_00_000);
1409+ }
1410+ goto default ;
1411+
13261412 default :
13271413 return null ;
13281414 }
@@ -1718,3 +1804,19 @@ struct TargetObjC
17181804
17191805// //////////////////////////////////////////////////////////////////////////////
17201806extern (C++ ) __gshared Target target;
1807+
1808+ private
1809+ {
1810+ // Define our own version of C prototypes, as older compilers didn't have
1811+ // the core.sys.*.sysctl module.
1812+ version (OSX )
1813+ {
1814+ extern (C ) int sysctlbyname(const char * name, void * oldp, size_t * oldlenp,
1815+ const void * newp, size_t newlen) nothrow @nogc ;
1816+ }
1817+ version (FreeBSD )
1818+ {
1819+ extern (C ) int sysctlbyname(const char * name, void * oldp, size_t * oldlenp,
1820+ const void * newp, size_t newlen) nothrow @nogc ;
1821+ }
1822+ }
0 commit comments