From 1789eedddb92dbb33b623f2f67d0b3680ce6a9f3 Mon Sep 17 00:00:00 2001 From: Murray Stevenson <50844517+murraystevenson@users.noreply.github.com> Date: Tue, 12 Nov 2024 17:46:11 +1100 Subject: [PATCH 1/4] SConstruct : Support building with Xcode 15 Xcode 15's new linker now complains when asked to link to the same library multiple times. I've removed the duplicates from the modules required to build a regular Cortex release, though I haven't touched the DCC specific modules. If the existing duplicate library specification turns out to be necessary for other platforms, we could alternately disable the linker warning here with `-no_warn_duplicate_libraries`. The new linker also complains that the `-single_module` flag is obsolete. `-single_module` became the default behaviour way back in OSX 10.4, so we should be fairly safe to remove it here. Disabling FMA via `--ffp-contract=off` fixes a test failure with `MeshPrimitiveEvaluator.pointAtUV()` returning an incorrect value in `TestMeshPrimitive.testPlane()`. Curiously, even with `--ffp-contract=off`, this test still fails when run on a virtualized instance of macOS. GitHub's macOS runners are vitualized, so we'll end up skipping this test when we enable macOS CI... --- SConstruct | 19 ++++++++++--------- include/IECore/MatrixInterpolator.inl | 2 +- test/IECore/InterpolatorTest.inl | 4 ++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/SConstruct b/SConstruct index d359269e9a..cc0e2f850a 100644 --- a/SConstruct +++ b/SConstruct @@ -1089,6 +1089,14 @@ if env["PLATFORM"] != "win32" : # deprecation of gluBuild2DMipmaps() in OSX 10.9. if osxVersion[0] == 10 and osxVersion[1] > 7 : env.Append( CXXFLAGS = [ "-Wno-unused-local-typedef", "-Wno-deprecated-declarations" ] ) + clangVersion = subprocess.check_output( [ env["CXX"], "-dumpversion" ], env=env["ENV"], universal_newlines=True ).strip() + clangVersion = [ int( v ) for v in clangVersion.split( "." ) ] + # Work around Boost issues with Xcode 15 where `std::unary_function` has been removed. + if clangVersion >= [ 15, 0, 0 ] : + env.Append( CXXFLAGS = [ "-DBOOST_NO_CXX98_FUNCTION_BASE", "-D_HAS_AUTO_PTR_ETC=0" ] ) + # Disable FMA on arm64 builds to limit floating point discrepancies with x86_64 builds. + if platform.machine() == "arm64" : + env.Append( CXXFLAGS = [ "-ffp-contract=off" ] ) elif env["PLATFORM"]=="posix" : if "g++" in os.path.basename( env["CXX"] ) and not "clang++" in os.path.basename( env["CXX"] ) : @@ -1304,11 +1312,11 @@ if doConfigure : Exit( 1 ) for line in open( str( boostVersionHeader ) ) : - m = re.compile( "^#define BOOST_LIB_VERSION \"(.*)\"\s*$" ).match( line ) + m = re.compile( r"^#define BOOST_LIB_VERSION \"(.*)\"\s*$" ).match( line ) if m : boostVersion = m.group( 1 ) if boostVersion : - m = re.compile( "^([0-9]+)_([0-9]+)(?:_([0-9]+)|)$" ).match( boostVersion ) + m = re.compile( r"^([0-9]+)_([0-9]+)(?:_([0-9]+)|)$" ).match( boostVersion ) boostMajorVersion, boostMinorVersion, boostPatchVersion = m.group( 1, 2, 3 ) env["BOOST_MAJOR_VERSION"] = boostMajorVersion env["BOOST_MINOR_VERSION"] = boostMinorVersion @@ -1494,9 +1502,6 @@ pythonModuleEnv = pythonEnv.Clone() pythonModuleEnv["SHLIBPREFIX"] = "" pythonModuleEnv["SHLIBSUFFIX"] = ".so" if env["PLATFORM"] != "win32" else ".pyd" -if pythonModuleEnv["PLATFORM"]=="darwin" : - pythonModuleEnv.Append( SHLINKFLAGS = "-single_module" ) - ########################################################################################### # An environment for running tests ########################################################################################### @@ -1940,9 +1945,7 @@ if doConfigure : imagePythonModuleEnv.Append( **imageEnvPrepends ) imagePythonModuleEnv.Append( LIBS = [ - os.path.basename( coreEnv.subst( "$INSTALL_LIB_NAME" ) ), os.path.basename( imageEnv.subst( "$INSTALL_LIB_NAME" ) ), - os.path.basename( corePythonEnv.subst( "$INSTALL_PYTHONLIB_NAME" ) ), ] ) imagePythonModule = imagePythonModuleEnv.SharedLibrary( "python/IECoreImage/_IECoreImage", imagePythonSources + imagePythonModuleSources ) @@ -2277,9 +2280,7 @@ if env["WITH_GL"] and doConfigure : glPythonModuleEnv.Append( **glEnvAppends ) glPythonModuleEnv.Append( LIBS = [ - os.path.basename( coreEnv.subst( "$INSTALL_LIB_NAME" ) ), os.path.basename( glEnv.subst( "$INSTALL_LIB_NAME" ) ), - os.path.basename( corePythonEnv.subst( "$INSTALL_PYTHONLIB_NAME" ) ), os.path.basename( imageEnv.subst( "$INSTALL_LIB_NAME" ) ), os.path.basename( sceneEnv.subst( "$INSTALL_LIB_NAME" ) ), ] diff --git a/include/IECore/MatrixInterpolator.inl b/include/IECore/MatrixInterpolator.inl index 26dcd0ca8f..ff15aa4722 100644 --- a/include/IECore/MatrixInterpolator.inl +++ b/include/IECore/MatrixInterpolator.inl @@ -130,7 +130,7 @@ struct CubicInterpolator< Imath::Matrix44< T > > Imath::Vec3 s0( 1 ), s1( 1 ), s2( 1 ), s3( 1 ), sx( 1 ); Imath::Vec3 h0( 0 ), h1( 0 ), h2( 0 ), h3( 0 ), hx( 0 ); - Imath::Vec3 r0( 0 ), r1( 0 ), r2( 0 ), r3( 0 ), rx( 0 ); + Imath::Vec3 r0( 0 ), r1( 0 ), r2( 0 ), r3( 0 ); Imath::Vec3 t0( 0 ), t1( 0 ), t2( 0 ), t3( 0 ), tx( 0 ); extractSHRT(y0, s0, h0, r0, t0); diff --git a/test/IECore/InterpolatorTest.inl b/test/IECore/InterpolatorTest.inl index 3c12edbe9b..1aeee14cd1 100644 --- a/test/IECore/InterpolatorTest.inl +++ b/test/IECore/InterpolatorTest.inl @@ -429,7 +429,7 @@ void MatrixCubicInterpolatorTest::testSimple() CubicInterpolator< Matrix > interp; CubicInterpolator< Vector > vectorInterp; - Vector s0( 1, 1, 1 ), h0( 0, 0, 0 ), r0( 0, 0, 0 ), t0( 5, 0, 0 ); + Vector s0( 1, 1, 1 ), h0( 0, 0, 0 ), t0( 5, 0, 0 ); Vector s1( 1, 2, 3 ), h1( 1, 2, 3 ), r1( 0, 1, 0 ), t1( 10, 0, 0 ); Vector s2( 0.5, 1.4, 5 ), h2( 2, 3, 4 ), r2( 0, 0.5, 0 ), t2( 20, 0, 0 ); Vector s3( 1, 2, 3 ), h3( 1, 2, 3 ), r3( 0, 1, 0 ), t3( 0, 0, 0 ); @@ -492,7 +492,7 @@ void MatrixCubicInterpolatorTest::testTyped() CubicInterpolator< MatrixData > interp; CubicInterpolator< Vector > vectorInterp; - Vector s0( 1, 1, 1 ), h0( 0, 0, 0 ), r0( 0, 0, 0 ), t0( 5, 0, 0 ); + Vector s0( 1, 1, 1 ), h0( 0, 0, 0 ), t0( 5, 0, 0 ); Vector s1( 1, 2, 3 ), h1( 1, 2, 3 ), r1( 0, 1, 0 ), t1( 10, 0, 0 ); Vector s2( 0.5, 1.4, 5 ), h2( 2, 3, 4 ), r2( 0, 0.5, 0 ), t2( 20, 0, 0 ); Vector s3( 1, 2, 3 ), h3( 1, 2, 3 ), r3( 0, 1, 0 ), t3( 0, 0, 0 ); From 926e5d748a15dbc797e112200ddf2dcdd3e189c9 Mon Sep 17 00:00:00 2001 From: Murray Stevenson <50844517+murraystevenson@users.noreply.github.com> Date: Tue, 12 Nov 2024 17:47:15 +1100 Subject: [PATCH 2/4] MeshAlgoDistributePointsTest : Remove unnecessary expectedFailures --- test/IECoreScene/MeshAlgoDistributePointsTest.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/test/IECoreScene/MeshAlgoDistributePointsTest.py b/test/IECoreScene/MeshAlgoDistributePointsTest.py index 5ad165f943..fdcae2a944 100644 --- a/test/IECoreScene/MeshAlgoDistributePointsTest.py +++ b/test/IECoreScene/MeshAlgoDistributePointsTest.py @@ -544,14 +544,6 @@ def setUp( self ) : os.environ["CORTEX_POINTDISTRIBUTION_TILESET"] = os.path.join( "test", "IECore", "data", "pointDistributions", "pointDistributionTileSet2048.dat" ) -if sys.platform == "darwin" : - - # These fail because MacOS uses libc++, and libc++ has a - # different `std::random_shuffle()` than libstdc++. - - MeshAlgoDistributePointsTest.testDensityMaskPrimVar = unittest.expectedFailure( MeshAlgoDistributePointsTest.testDensityMaskPrimVar ) - MeshAlgoDistributePointsTest.testDistanceBetweenPoints = unittest.expectedFailure( MeshAlgoDistributePointsTest.testDistanceBetweenPoints ) - if __name__ == "__main__": unittest.main() From bee969ebcfce4a60fd36b56cc9e80cdf58e0eb74 Mon Sep 17 00:00:00 2001 From: Murray Stevenson <50844517+murraystevenson@users.noreply.github.com> Date: Tue, 12 Nov 2024 17:47:56 +1100 Subject: [PATCH 3/4] SceneCacheFilterFormatTest : Enable test on macOS --- contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py b/contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py index 7a4a6778fc..f943a2706d 100644 --- a/contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py +++ b/contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py @@ -47,7 +47,6 @@ import IECoreScene import IECoreUSD -@unittest.skipIf( sys.platform == 'darwin', "plugInfo.json fails to register on GitHub Actions Macos container." ) class SceneCacheFileFormatTest( unittest.TestCase ) : def setUp( self ) : From 39dd46b1b81f0edb103e09eba2b484f8fb33c242 Mon Sep 17 00:00:00 2001 From: Murray Stevenson <50844517+murraystevenson@users.noreply.github.com> Date: Tue, 12 Nov 2024 17:50:14 +1100 Subject: [PATCH 4/4] CI : Add macos-arm64 builds These builds lack signing and notarization and are published chiefly for our own use. Making the build artifacts available, even in their current state, paves the way towards re-establishing Gaffer CI runs on macOS. --- .github/workflows/main.yml | 28 +++++++++++++++++----------- test/IECoreScene/MeshPrimitive.py | 2 +- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9f71605ebd..7a749051e8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -33,7 +33,8 @@ jobs: linux-gcc11, linux-debug-gcc11, windows, - windows-debug + windows-debug, + macos-arm64 ] include: @@ -46,6 +47,7 @@ jobs: dependenciesURL: https://github.com/GafferHQ/dependencies/releases/download/8.0.1/gafferDependencies-8.0.1-linux-gcc11.tar.gz tests: testCore testCorePython testScene testImage testAlembic testUSD testVDB publish: true + jobs: 4 - name: linux-debug-gcc11 os: ubuntu-20.04 @@ -55,6 +57,7 @@ jobs: dependenciesURL: https://github.com/GafferHQ/dependencies/releases/download/8.0.1/gafferDependencies-8.0.1-linux-gcc11.tar.gz tests: testCore testCorePython testScene testImage testAlembic testUSD testVDB publish: false + jobs: 4 - name: windows os: windows-2019 @@ -63,6 +66,7 @@ jobs: dependenciesURL: https://github.com/GafferHQ/dependencies/releases/download/8.0.1/gafferDependencies-8.0.1-windows.zip tests: testCore testCorePython testScene testImage testAlembic testUSD testVDB publish: true + jobs: 4 - name: windows-debug os: windows-2019 @@ -71,6 +75,16 @@ jobs: dependenciesURL: https://github.com/GafferHQ/dependencies/releases/download/8.0.1/gafferDependencies-8.0.1-windows.zip tests: testCore testCorePython testScene testImage testAlembic testUSD testVDB publish: false + jobs: 4 + + - name: macos-arm64 + os: macos-14 + buildType: RELEASE + options: .github/workflows/main/options.posix + dependenciesURL: https://github.com/GafferHQ/dependencies/releases/download/9.0.0/gafferDependencies-9.0.0-macos-arm64.tar.gz + tests: testCore testCorePython testScene testImage testAlembic testUSD testVDB + publish: true + jobs: 3 runs-on: ${{ matrix.os }} @@ -92,16 +106,8 @@ jobs: if: runner.os == 'Windows' - name: Install toolchain (MacOS) - # Prefer `pip install` because it is faster - # than `brew install`. run: | - sudo pip3 install scons==4.0.1 - # Brew installs all manner of headers into `/usr/local/include`, including - # OpenEXR and Imath versions that conflict with our own. We can't stop Clang - # finding them because Clang is hardcoded to look in `/usr/local/include` - # _before_ anything we specify with `-isystem`, despite documentation to the - # contrary. So we nuke the headers. - rm -rf /usr/local/include/* + pipx install scons==4.6.0 echo PACKAGE_COMMAND=tar -czf >> $GITHUB_ENV echo PACKAGE_EXTENSION=tar.gz >> $GITHUB_ENV if: runner.os == 'macOS' @@ -154,7 +160,7 @@ jobs: - name: Build run: | - scons -j 4 BUILD_TYPE=${{ matrix.buildType }} OPTIONS=${{ matrix.options }} BUILD_CACHEDIR=sconsCache + scons -j ${{ matrix.jobs }} BUILD_TYPE=${{ matrix.buildType }} OPTIONS=${{ matrix.options }} BUILD_CACHEDIR=sconsCache # Copy the config log for use in the "Debug Failures" step, because it # gets clobbered by the `scons test*` call below. cp config.log buildConfig.log diff --git a/test/IECoreScene/MeshPrimitive.py b/test/IECoreScene/MeshPrimitive.py index 7ffd78aca1..1250569862 100644 --- a/test/IECoreScene/MeshPrimitive.py +++ b/test/IECoreScene/MeshPrimitive.py @@ -266,7 +266,7 @@ def testBox( self ) : self.assertEqual( len( m["N"].data ), 6 ) self.assertEqual( len( m["uv"].indices ), m.variableSize( IECoreScene.PrimitiveVariable.Interpolation.FaceVarying ) ) - + @unittest.skipIf( IECore.TestUtil.inMacCI(), "Incorrect pointAtUV results on virtualized macOS used in CI" ) def testPlane( self ) : m = IECoreScene.MeshPrimitive.createPlane( imath.Box2f( imath.V2f( 0 ), imath.V2f( 1 ) ) )