2626module dmd.target ;
2727
2828import core.stdc.stdio ;
29+ import core.stdc.stdlib ;
2930
3031import dmd.astenums : CHECKENABLE ;
3132import dmd.globals : Param;
@@ -350,6 +351,7 @@ extern (C++) struct Target
350351
351352 OS os;
352353 ubyte osMajor;
354+ uint osVersionLong; // / major, minor, patch version for getTargetInfo.
353355
354356 // D ABI
355357 ubyte ptrsize; // / size of a pointer in bytes
@@ -1275,14 +1277,17 @@ extern (C++) struct Target
12751277 }
12761278 }
12771279
1278- // this guarantees `getTargetInfo` and `allTargetInfos` remain in sync
1280+ // NOTE: If `allTargetInfos` gets implemented, the platform-specific keys
1281+ // should be moved to a separate enum.
12791282 private enum TargetInfoKeys
12801283 {
12811284 cppRuntimeLibrary,
12821285 cppStd,
12831286 floatAbi,
12841287 objectFormat,
1285- CET
1288+ CET ,
1289+ OSXVersion,
1290+ FreeBSDVersion,
12861291 }
12871292
12881293 /**
@@ -1303,6 +1308,11 @@ extern (C++) struct Target
13031308 {
13041309 return new StringExp(loc, sval);
13051310 }
1311+ IntegerExp osVersion (uint v)
1312+ {
1313+ osVersionLong = v;
1314+ return new IntegerExp(v);
1315+ }
13061316
13071317 switch (name.toDString) with (TargetInfoKeys)
13081318 {
@@ -1323,6 +1333,91 @@ extern (C++) struct Target
13231333 case CET .stringof:
13241334 return new IntegerExp(driverParams.ibt);
13251335
1336+ case OSXVersion.stringof:
1337+ if (os == Target.OS .OSX )
1338+ {
1339+ // Format of the version: XX_YY_ZZ
1340+ if (osVersionLong)
1341+ return new IntegerExp(osVersionLong);
1342+
1343+ static uint macOSVersion (uint darwin)
1344+ {
1345+ // Darwin25 maps to macOS 26
1346+ if (darwin >= 25 )
1347+ return (darwin + 1 ) * 1_00_00;
1348+ // Darwin20 to 24 maps to macOS 11 to 15
1349+ else if (darwin >= 20 )
1350+ return (darwin - 9 ) * 1_00_00;
1351+ // Darwin4 to 19 map to macOS 10.0 to 10.15
1352+ else if (darwin >= 4 )
1353+ return 10_00_00 + ((darwin - 4 ) * 1_00);
1354+ return 0 ;
1355+ }
1356+ // Infer from the requested deployment target.
1357+ if (const env = getenv(" MACOSX_DEPLOYMENT_TARGET" ))
1358+ {
1359+ uint major, minor, tiny;
1360+ if (sscanf (" %u.%u.%u" , &major, &minor, &tiny) >= 0 )
1361+ return osVersion ((major * 1_00_00) + (minor * 1_00) + tiny);
1362+ }
1363+ // Infer from -target= os version (i.e: darwin20)
1364+ if (auto macVersion = macOSVersion(osMajor))
1365+ return osVersion (macVersion);
1366+ // Infer from the running system.
1367+ version (OSX )
1368+ {
1369+ char [32 ] buf = 0 ;
1370+ size_t length = buf.length;
1371+ uint major, minor, tiny;
1372+ if (sysctlbyname(" kern.osproductversion" , buf.ptr, &length, null , 0 ) == 0 )
1373+ {
1374+ // Returns the macOS version string, e.g: 12.6.0
1375+ if (sscanf(buf.ptr, " %u.%u.%u" , &major, &minor, &tiny) >= 0 )
1376+ return osVersion ((major * 1_00_00) + (minor * 1_00) + tiny);
1377+ }
1378+ if (sysctlbyname(" kern.osrelease" , buf.ptr, &length, null , 0 ) == 0 )
1379+ {
1380+ // Returns the darwin version string, map to macOS.
1381+ if (sscanf(buf.ptr, " %u.%u.%u" , &major, &minor, &tiny) >= 0 )
1382+ {
1383+ if (auto macVersion = macOSVersion(major))
1384+ return osVersion (macVersion);
1385+ }
1386+ }
1387+ }
1388+ // Fallback on guessing appropriate minimum version.
1389+ if (isAArch64)
1390+ return osVersion (11_00_00);
1391+ else if (isX86_64)
1392+ return osVersion (10_06_00);
1393+ else
1394+ return osVersion (10_05_00);
1395+ }
1396+ goto default ;
1397+
1398+ case FreeBSDVersion.stringof:
1399+ if (os == Target.OS .FreeBSD)
1400+ {
1401+ // Format of the version: XX_YY_ZZZ
1402+ if (osVersionLong)
1403+ return new IntegerExp(osVersionLong);
1404+
1405+ // Infer from -target= os version (i.e: freebsd13)
1406+ if (osMajor)
1407+ return osVersion (osMajor * 1_00_000);
1408+ // Infer from the running system.
1409+ version (FreeBSD )
1410+ {
1411+ int osreldate;
1412+ size_t length = int .sizeof;
1413+ if (sysctlbyname(" kern.osreldate" , &osreldate, &length, null , 0 ) == 0 )
1414+ return osVersion (osreldate);
1415+ }
1416+ // Fallback to minimum supported version.
1417+ return osVersion (10_00_000);
1418+ }
1419+ goto default ;
1420+
13261421 default :
13271422 return null ;
13281423 }
@@ -1718,3 +1813,19 @@ struct TargetObjC
17181813
17191814// //////////////////////////////////////////////////////////////////////////////
17201815extern (C++ ) __gshared Target target;
1816+
1817+ private
1818+ {
1819+ // Define our own version of C prototypes, as older compilers didn't have
1820+ // the core.sys.*.sysctl module.
1821+ version (OSX )
1822+ {
1823+ extern (C ) int sysctlbyname(const char * name, void * oldp, size_t * oldlenp,
1824+ const void * newp, size_t newlen) nothrow @nogc ;
1825+ }
1826+ version (FreeBSD )
1827+ {
1828+ extern (C ) int sysctlbyname(const char * name, void * oldp, size_t * oldlenp,
1829+ const void * newp, size_t newlen) nothrow @nogc ;
1830+ }
1831+ }
0 commit comments