Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Needs universal framework build on macOS Big Sur #18049

Closed
MainasuK opened this issue Aug 6, 2020 · 22 comments · Fixed by #18094
Closed

Needs universal framework build on macOS Big Sur #18049

MainasuK opened this issue Aug 6, 2020 · 22 comments · Fixed by #18094

Comments

@MainasuK
Copy link

MainasuK commented Aug 6, 2020

System information (version)
  • OpenCV => 4.4.0
  • Operating System / Platform => macOS 11.0
  • Compiler => CMake
Detailed description

I found a temporary workaround to build arm64 opencv2.framework on the DTK with Apple Silicon. And cross build should works but the try failed on the intel machine. (Intel and Apple Silicon could build arm64 & x86_64. Both could run x86_64 (via Rosetta). But arm64 running is Apple Silicon only).

Prepare:

  • opencv-4.4.0
  • opencv_contrib-4.4.0
  • native cmake from: brew install -s cmake

With:

  • arm64 DTK
  • macOS 11.0 Beta 4
  • Xcode 12 Beta 4

Build:

  1. Change the build_framework.py line 62: "x86_64" to "arm64"
  2. % ./opencv-4.4.0/platforms/osx/build_framework.py ./opencv-framework-4.4.0 --contrib ./opencv_contrib-4.4.0 --enable_nonfree --disable CAROTENE
  3. get opencv2.framework output

Test:

  1. % ./opencv-4.4.0/platforms/osx/run_tests.py --framework_dir=/Users/mainasuk/Developer/opencv-framework-4.4.0 --framework_name=opencv2 /Users/mainasuk/Developer/opencv-framework-4.4.0/build/build-arm64-macosx/modules/objc/test
  2. fail with error: "Unable to find a destination matching the provided destination specifier: { platform:macOS, arch:x86_64 }"
  3. open OpenCVTest.xcodeproj under /Users/mainasuk/Developer/opencv-framework-4.4.0/build/build-arm64-macosx/modules/objc/test_build
  4. In the Build Settings set project Architectures to "Standard Architectures(64-bit Intel and ARM) - $(ARCHS_STANDARD)"
  5. Run unit tests get compile error "Type of expression is ambiguous without more context" on line 27
    func testPoint2dToMat() {
        let pointsIn = [Point2d(x:3.80004, y:73.2), Point2d(x:16.01, y:7.1111), Point2d(x:3.14, y:6), Point2d(x:-78, y:14)]
        let pointsOut = Converters.Mat_to_vector_Point2d(Converters.vector_Point2d_to_Mat(pointsIn))
        XCTAssertEqual(pointsIn, pointsOut)    <<< here
    }
  1. The pointsIn with type [Point2d] and pointsOut with [Point2f]
  2. Comment out the line 27
  3. All unit tests pass (skip testPoint2dToMat)

I have a Swift port repo for OpenCV. After create folder "Frameworks" under the root and move the opencv2.framework into it. All demo program in OpenCVBridge.xcodeproj run identically as the Intel Mac.

And here are 3 problems for that.

  1. Disable CAROTENE fix arm64 build fail. I have no idea about that so temporary disable it. Maybe it's could be fixed.
  2. The universal cross build framework needs with x86_64 and arm64 archs. Rosetta works for Intel app but arm64 arch is required for a native build.
  3. Fix needs for testPoint2dToMat unit test. :)

I hope that transform will not so hard.

@asmorkalov
Copy link
Contributor

@komakai could you help with the issue?

@komakai
Copy link
Contributor

komakai commented Aug 10, 2020

@asmorkalov @MainasuK

Disable CAROTENE fix arm64 build fail. I have no idea about that so temporary disable it. Maybe it's could be fixed.

I believe CAROTENE was contributed by NVIDIA - maybe they could help get it to work on Apple Silicon. If I'm correct it contains optimization for ARM processors so it would definitely be good to fix this

universal cross build framework

The iOS build script is creating a Universal build script - so we could probably copy ideas from their

Fix needs for testPoint2dToMat unit test

Looks like adding a cast somewhere would fix that

2 and 3 I can probably take a look at but I don't have a machine running Big Sur beta yet so it will take a while to get myself set up.

@asmorkalov
Copy link
Contributor

Carotene library contains functions implementations with ARM NEON intrinsics. There is nothing specific to NVIDIA, it should be just general compilation issue.

@komakai
Copy link
Contributor

komakai commented Aug 10, 2020

I found a careless mistake in my code that is probably what caused the test to fail. Have created #18065 for that.
@MainasuK can you share the compile errors you get when building with CAROTENE enabled?

@MainasuK
Copy link
Author

The log from: % ./opencv-4.4.0/platforms/osx/build_framework.py ./opencv-framework-4.4.0 --contrib ./opencv_contrib-4.4.0 --enable_nonfree 2>&1 | tee build.log

build.log

There is one line error message about missing numpy module and I can not install numpy yet. That's another issue.

@mshabunin
Copy link
Contributor

Carotene compilation should've been fixed here: #17987 Please try latest 3.4 or master branch version.

@MainasuK
Copy link
Author

I use the DTK to build the framework for arm64 on master without any issue.

And test on the different machines with the same environment:

  • macOS Big Sur Dev Beta 4
  • Xcode 12 Beta 4

DTK:

Intel mac:

@mshabunin
Copy link
Contributor

To build for arm64 on Intel machine, you have to provide cmake toolchain file for cross-compilation or pass the following parameters:

 cmake \
     -GXcode \
     -DCMAKE_SYSTEM_PROCESSOR=arm64 \
     -DCMAKE_OSX_ARCHITECTURES=arm64 \
     -DWITH_OPENJPEG=OFF \
     -DWITH_IPP=OFF \
../opencv

Probably something similar is required for cross-compilation on DTK for IA, but I don't have this system and can not test it.

@komakai
Copy link
Contributor

komakai commented Aug 11, 2020

@MainasuK I had a look at the macOS build scripts and there is a possibility that just the following simple change could work:

komakai@c33a1e6

Could you try building with that change and with the below command line?

./opencv/platforms/osx/build_framework.py --archs=x86_64,arm64 opencv_output_dir

@komakai
Copy link
Contributor

komakai commented Aug 11, 2020

@MainasuK Ah sorry - this patch is not enough. We will need to create something equivalent to the platforms\ios\cmake\Modules and platforms\ios\cmake\Toolchains folders for macOS - that will take a bit longer.

@MainasuK
Copy link
Author

MainasuK commented Aug 11, 2020

@komakai The same error when building x86_64 on the DTK. And If the --archs set as arm64,x86_64. The arm64 part works. I guess the CAROTENE breaks cross build on the DTK after several times trying. I disable it and turn off NEON too. Then the x86_64 cross build works.

Disable NEON:
In ./platforms/ios/build_framework.py

def getCMakeArgs(self, arch, target):
        args = [
            "cmake",
            "-GXcode",
            "-DAPPLE_FRAMEWORK=ON",
            "-DENABLE_NEON=OFF",        <<<< add this
            "-DCMAKE_INSTALL_PREFIX=install",
            "-DCMAKE_BUILD_TYPE=%s" % self.getConfiguration(),
            "-DOPENCV_INCLUDE_INSTALL_PATH=include",
            "-DOPENCV_3P_LIB_INSTALL_PATH=lib/3rdparty",
            "-DFRAMEWORK_NAME=%s" % self.framework_name,
            ...

I use that command to make the universal framework without error.
./opencv-macos-universal-binary/platforms/osx/build_framework.py --archs=x86_64,arm64 ./opencv-framework-universal --contrib ./opencv_contrib-4.4.0 --enable_nonfree --disable CAROTENE 2>&1 | tee ./opencv-framework-universal/DTK-build-universal.log

Framework and build log upload to Dropbox.

Check archs:

% lipo -archs opencv2.framework/opencv2
x86_64 arm64

Maybe could disable CAROTENE and NEON for x86_64 build only. Because they are ARM only.

And I make a universal build for my side-project ImageReader with the universal framework. The app natively running on the DTK and Intel mac without any issue. Only crash when using Rosetta and that's doesn't matter.

Thanks a lot and I'm glad to help if needs building tests.
(I can test the DTK build and Intel Big Sur Mac build. But not at the same time. The two machines locate the different places. Both can not mobile. But ASAP :D)

@komakai
Copy link
Contributor

komakai commented Aug 13, 2020

I downloaded Xcode 12 beta4 and had another attempt at this:
komakai@e2c9156
Building on x86_64 with -archs=arm64,x86_64 I was able to successfully build a Universal framework.
Should work the other way round as well

@MainasuK
Copy link
Author

MainasuK commented Aug 13, 2020

I try to build the universal framework with the new commit on the DTK. And the camke report a configure error and returned. DTK-build.log

I notice when building x86_64 the log says:

--   CPU/HW features:
--     Baseline:
--       requested:                 DETECT
--       required:                  NEON
--       disabled:                  VFPV3

Maybe "-DCPU_BASELINE=DETECT" not mark the NEON off. So I add this just after your changes.

            if arch != "arm64":
                cmakecmd.append("-DENABLE_NEON=OFF")

Then the universal build works. And I'm trying to use the framework and see if have any error. Update it soon.
DTK-build-works.log

Update:
The application running without issue and the unit tests pass. It works well.
Thank you all contributors.

@komakai
Copy link
Contributor

komakai commented Aug 13, 2020

@MainasuK thanks for testing - I'll make a PR now
Also thanks to @mshabunin for the hint on cross-compiling

@komakai
Copy link
Contributor

komakai commented Aug 23, 2020

@MainasuK could you try building komakai@fdcbd8d on the DTK and see if the x86_64 build works correctly?

@MainasuK
Copy link
Author

I test the new commit. The universal framework built on the DTK works.

build.log

@komakai
Copy link
Contributor

komakai commented Aug 24, 2020

@MainasuK thanks for testing - looks like the new patch is an improvement on the first attempts

@LGriffioen
Copy link

Hi,

I'm working on getting a macOS app compiling on  Silicon and I'm having some trouble building OpenCV for arm64. I'm using the CMake app to build the dylibs (we don't need the entire framework) and I'm using the 4.5.0-openvino release.

Is this supported as of that release? If so, I have some more questions below the fold. If not, is that coming soon?


The first problem is I don't seem to be able to compile for x86 and arm at the same time. I just get invalid architecture. Is it possible to build a universal binary?

The second is if I try to build for just arm, I immediately get compilation errors when I attempt to make

/Users/l.griffioen/Downloads/opencv-4.5.0-openvino/3rdparty/libjasper/jas_getopt.c:129:25: error: 
      implicit declaration of function 'jas_eprintf' is invalid in C99
      [-Werror,-Wimplicit-function-declaration]
                        jas_eprintf("unknown long option %s\n", s);
                        ^
/Users/l.griffioen/Downloads/opencv-4.5.0-openvino/3rdparty/libjasper/jas_getopt.c:140:25: error: 
      implicit declaration of function 'jas_eprintf' is invalid in C99
      [-Werror,-Wimplicit-function-declaration]
                        jas_eprintf("unknown short option %s\n", s);
                        ^
/Users/l.griffioen/Downloads/opencv-4.5.0-openvino/3rdparty/libjasper/jas_getopt.c:151:25: error: 
      implicit declaration of function 'jas_eprintf' is invalid in C99
      [-Werror,-Wimplicit-function-declaration]
                        jas_eprintf("missing argument for option %s\n", s);
                        ^
3 errors generated.
make[2]: *** [3rdparty/libjasper/CMakeFiles/libjasper.dir/jas_getopt.c.o] Error 1
make[1]: *** [3rdparty/libjasper/CMakeFiles/libjasper.dir/all] Error 2
make: *** [all] Error 2

My command line tools are pointed at Xcode 12.2 beta 2 and I'm on Catalina. Do I need to be on Big Sur / the DTK to compile this?

Any help would be appreciated! (also if this isn't the best place for this discussion, I'd be happy to move it elsewhere.)

@komakai
Copy link
Contributor

komakai commented Oct 12, 2020

@LGriffioen building with this command line is known to work (i.e. produce a universal binary):
./opencv/platforms/osx/build_framework.py --archs=x86_64,arm64 opencv_output_dir

If you are building some other way then your results may vary.

@alalek any chance you could add "Support for Apple Silicon" to the ChangeLog for release 4.5 ? (Much appreciated!)

@sayakpaul
Copy link

I wrote a comprehensive blog post that shows how to build and install OpenCV on an M1 MacBook - https://sayak.dev/install-opencv-m1/. Hopefully, it turns out to be useful.

@luvwinnie
Copy link

@sayakpaul Hi I'm facing this problem, do you know how to solve this?

undefined symbols for architecture arm64:
  "_png_do_expand_palette_rgba8_neon", referenced from:
      _png_do_read_transformations in liblibpng.a(pngrtran.c.o)
  "_png_init_filter_functions_neon", referenced from:
      _png_read_filter_row in liblibpng.a(pngrutil.c.o)
  "_png_riffle_palette_neon", referenced from:
      _png_do_read_transformations in liblibpng.a(pngrtran.c.o)
  "_png_do_expand_palette_rgb8_neon", referenced from:
      _png_do_read_transformations in liblibpng.a(pngrtran.c.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [lib/libopencv_imgcodecs.4.5.0.dylib] Error 1
make[1]: *** [modules/imgcodecs/CMakeFiles/opencv_imgcodecs.dir/all] Error 2
make: *** [all] Error 2

@ansoni-san
Copy link

ansoni-san commented Feb 5, 2021

It likely linked with an x86_64 version of libpng.

You'll need to install the dependencies to different locations. The current convention is installing arm64 libraries using a homebrew instance under /opt/homebrew (and thus all resulting arm64 libraries being under there as well), and then reserving /usr/local for the x86_64 libraries.

Then you can simply switch your library and include paths using compiler and linker flags. Official homebrew advice on multiple installs (and specifically ARM vs Intel): https://docs.brew.sh/Installation#alternative-installs

Quick Example

1 - This command will create the second homebrew installation for you:

/bin/bash -c "$(curl -fsSL https://gist.githubusercontent.com/nrubin29/bea5aa83e8dfa91370fe83b62dad6dfa/raw/48f48f7fef21abb308e129a80b3214c2538fc611/homebrew_m1.sh)"

2 - You then install the dependencies using:

arch -arm64 /opt/homebrew/bin/brew install <whatever>

arch -x86_64 /usr/local/bin/brew install <whatever>

You then just need to switch LDFLAGS and CFLAGS out when changing between target architectures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

9 participants