[OpenCV] Source build

OpenCV를 사용하는데 여러 방법이 있겠지만 SBC 컴퓨터들에서 소스로 빌드해서 사용해야할 경우가 있다.

OpenCV 소스 빌드

여기서 OpenCV를 개발 도구와 라이브러리들과 함게 소스를 빌드해서 사용하는 방법을 살펴보겠습니다.

  • Raspberry Pi 3: Raspbian Jessie
  • Odroid C2: Armbian
  • ROCK64: Armbian

빌드는 OpenCV 3.1.1 버전을 대상으로 수행했다.

OpenCV3.1 빌드로 설치

http://docs.opencv.org/3.1.0/df/d65/tutorial_table_of_content_introduction.html

OpenCV 3.1를 빌드하는데 필요한 패키지

  • GCC 4.4.x or later
  • CMake 2.8.7 or higher
  • Git
  • GTK+2.x or higher, including headers (libgtk2.0-dev)
  • pkg-config
  • Python 2.6 or later and Numpy 1.5 or later with developer packages ( python-dev, python-numpy)
  • ffmpeg or libav development packages: libavcodec-dev, libavformat-dev, libswscale-dev
  • [optional] libtbb2 libtbb-dev
  • [optional] libdc1394 2.x
  • [optional] libjpeg-dev, libpng-dev, libtiff-dev, libjasper-dev, libdc1394-22-dev

그리고 VideoStreaming이 필요하면 gstramer 필요.

패키지 설치

기존 패키지로 설치되 opencv가 있으면 제거한다.

1
2
$ sudo apt remove libopencv
$ sudo apt remove opencv

최신 소프트웨어 상태로 업데이트 합니다.

1
2
$ sudo apt update
$ sudo apt upgrade

먼저 컴파일러와 빌드 관련 패키지를 설치합니다.

1
2
$ sudo apt install build-essential
$ sudo apt install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev

GTK 개발용 라이브러리는 GUI를 구성할 때 필요하다.

1
$ sudo apt install libgtk-3-dev

이미지 처리에 필요한 패키지를 설치한다.

1
$ sudo apt install libgphoto2-dev libjpeg-dev  libtiff-dev libtiff5-dev libjasper-dev libpng12-dev libpng-dev
  • libtbb2 libtbb-dev

필요하다면 비디오 입출력 관련한 패키지를 설치해야 한다. OpenCV에서 비디오 파일을 읽는데 필요하다.

1
$ sudo apt install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev

libdc1394-22-dev

필요하면 스트리밍 처리에 필요한 gstreamer를 설치한다.

1
$ sudo apt install gstreamer-1.0

OpenCV 안에서 다양한 최적화 작업에 필요한 다음 패키지를 설치한다.

1
$ sudo apt install libatlas-base-dev gfortran

마지막으로 파이썬에서 사용한다면 꼭 numpy 를 설치해야 한다. numpy 는 pip로 설치해야 한다.

  • OpenCV Python에서 이미지를 NumPy의 다차원배열로 표현해 사용하고 있다:

시스템에 Python2.7과 python3.4가 설치되어 있다면, 각 pip버전을 명시해서 각각 설치해야 하는 듯 하다. numpy가 제대로 인식이 안되면 Opencv용 python 모듈이 빌드가 안된다.

Raspbian jessie 2016-09-23 버전 이후에는 numpy가 기본으로 설치되어 있다.

1
2
~$ sudo pip2 install numpy
~$ sudo pip3 install numpy
  • Raspberry Pi 2에서 numpy를 pip로 설치할 때 약 10분 이상 소요된다.

혹은 업그레이드 해준다.

1
2
$ sudo pip2 install --upgrade numpy
$ sudo pip3 install --upgrade numpy

numpy 설치후 다음 같이 제대로 동작하는지 확인해 보자

1
2
3
4
5
6
7
8
9
10
11
$:~ $ python2
...

$:~ $ python3
Python 3.4.2 (default, Oct 19 2014, 13:31:11)
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> np.__version__
'1.10.4'
>>>

파이썬에서 사용하려면 다음 같이 파이썬 관련 라이브러리가 필요

1
$ sudo apt install python-dev python3-dev python-numpy python3-numpy

개발환경을 apt 방식으로 구성했다면, numpy도 apt로 설치 할 수 있다 – 왠지 잘 안됐다.
$ sudo apt install python-numpy

마지막으로 파이썬에서 matplotlib를 이용한다면 python3-gtk 패키지를 설치해 준다.

1
$sudo apt install python3-gtk

Opencv 다운로드 및 빌드 확경 구성

1
2
3
4
$ cd ~
$ git clone https://github.com/Itseez/opencv.git
$ cd opencv
$ git checkout 3.1.0

빌드를 설정하기 위해서 build폴더를 만든다.

파이썬 환경이 있는 cv 가상환경

build 를 준비

1
2
3
~$ cd opencv
~$ mkdir build
~$ cd build

빌드를 수행

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
~$ cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D INSTALL_C_EXAMPLES=OFF \
-D INSTALL_PYTHON_EXAMPLES=ON \
-D BUILD_EXAMPLES=ON ..

...
-- Python 2:
-- Interpreter: /usr/bin/python2.7 (ver 2.7.9)
--
-- Python 3:
-- Interpreter: /usr/bin/python3.4 (ver 3.4.2)
--
-- Python (for build): /usr/bin/python2.7


위 스크립은 OpenCV 3.1.0의 CMake 빌드 버그로, OpenCV 3.0.0 까지 -D INSTALL_C_EXAMPLES=ON으로 빌드했지만 3.1.0에서는 -D INSTALL_C_EXAMPLES=OFF로 해야한다.
또한 opencv_contrib 모듈을 함께 빌드한다면 -D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules를 함께 사용한다.

컴파일과 설치

그리고 컴파일 한다.

1
2
3
4
5
6
7
8
~(cv)$ make -j4       # RPi2

...
[100%] Built target example_ocl_tvl1_optical_flow

real 173m22.432s
user 165m58.970s
sys 5m7.060s

싱글로 make시 Raspberry Pi 2 에서 빌드시 약 3시간 소요.
-j 옵션을 이용시 45분 이상 절약.

빌드된 결과중에 python2, python3 관련해서 라이브러리가 제대로 빌드되었는지 라이브러리 폴더를 확인한다.

1
2
$ ls lib/cv2.so
$ ls lib/python3/cv2.cpython-34m.so

이 두 라이브러리가 생성되 있으면 빌드가 제대로 된 것이다.

이제 로컬 시스템에 설치를 한다. 보통 Python2.7과 Python3.4가 함께 설치되 상태일 수 있는데 이 경우 시스템에 기본 Python2.7 환경을 기반으로 설치가 된다.

1
2
3
4
5
6
7
8
9
10
(cv)$ sudo make install
...
-- Installing: /usr/local/include/opencv2/contrib/detection_based_tracker.hpp
-- Installing: /usr/local/lib/python2.7/dist-packages/cv2.so
-- Set runtime path of "/usr/local/lib/python2.7/dist-packages/cv2.so" to "/usr/local/lib"
-- Installing: /usr/local/lib/python2.7/dist-packages/cv.py
-- Installing: /usr/local/lib/libopencv_stitching.so.2.4.11
...

(cv)$ sudo ldconfig

설치된 opencv 패키지 버전을 확인한다.

1
2
$ pkg-config --modversion opencv
3.1.0

cv2.so

Python2.7이 함께 설치되어 있는 경우 빌드시 Python3.x의 site-packages에 파일 cv2.cpython-34mu.so 로 설치되어 있다. 이 파일은 실제 파이썬 바인딩으로 실제 파이썬 환경에서 이 라이브러리가 필요하기 하다. Python3 가상환경에서 이 파일 심볼릭 링크를 cv 환경에 cv2.so라는 이름으로 연결해 준다.

파이썬은 관행적으로 opencv 라이브러리를 cv2.so 파일로 표현하고 있다. python3의 경우 라이브러리 이름을 cv2로 링크해 준다.

1
2
3
4
$ cd /usr/local/lib/python3.4/dist-packages
$ ls
cv2.cpython-34m.so numpy numpy-1.11.2.egg-info
$ sudo ln -s cv2.cpython-34m.so cv2.so

Build ffmpeg - macOS

Mac OS X 에서 ffmpeg 빌드

Android OS에 사용할 ffmpeg를 macOS에서 크로스컴파일러로 빌드해서 포팅하는 과정을 담고 있다.
필요한 것은

  • homebrew
  • xcode command line
  • Android NDK stanalone toolchain

준비할 것

Homebrew 를 이용한 빌드를 위해서 xcode와 homebrew 설치가 필요하다.

Xcode 최신버전들은 Command line tool을 수동으로 설치해야 한다.

  • Xcode를 실행하여 ‘Preferences > Downloads > Command Line Tools’ 항목을 설치

homebrew 설치

1
ruby <(curl -fsSkL raw.github.com/mxcl/homebrew/go)

그리고 homebrew doctor 명령을 실행해 설치 환경과 내용이 이상 없는지 확인한다.

1
homebrew doctor

update로 포뮬라들을 최신으로 갱신해 준다.

1
brew update

homebrew에서 설치하는 개체를 Ruby script로 패키지에 대해 선언한 명세서를 Formula라고 하고 install 명령에 의해 /usr/local/Library/Formula 에 설치한다.

homebrew에서 패키지를 하나 설치한다.

1
$ brew install wget

그리고 패키지의 업그레이드, 제거는 다음과 같다.

1
2
brew upgrade [foo]
brew uninstall [foo]

의존성 패키지 설치

ffmpeg 에 필요한 의존선 패키지를 설치한다.

1
2
3
4
brew install automake celt faac fdk-aac git \
lame libass libtool libvorbis libvpx libvo-aacenc \
opencore-amr openjpeg opus sdl schroedinger shtool \
speex texi2html theora wget x264 xvid yasm

Install libaacplus (atm. there is no recipe for it) 컴파일 환경에 대해 [^1]를 참조했다.

1
2
3
wget http://217.20.164.161/~tipok/aacplus/libaacplus-2.0.2.tar.gz
tar xzf libaacplus-2.0.2.tar.gz
cd libaacplus-2.0.2

libtool on osx is quite different from the gnu libtool, which is called glibtool on osx

1
2
3
4
5
6
7
cat autogen.sh | sed 's/libtool/glibtool/' > autogen2.sh


sed -i '.bck' -e 's/libtool/glibtool/' autogen.sh
./autogen.sh
make && make install
cd ..

Standalone toolchain

http://goo.gl/P20dD

Standalone toolchain은 Android NDK 최근 버전부터 추가된 기능입니다. 이걸 사용하면 ndk-build 명령을 쓰지 않고 기존의 configure -> make를 사용하던 컴파일 과정을 그대로 사용해서 라이브러리를 컴파일 할 수 있습니다.

ndk를 통해서 toolchain을 빌드한다. 자세한 사항은 STANDALONE-TOOLCHAIN  참조한다.

1
2
3
4
$ {NDK}/build/tools/make-standalone-toolchain.sh \
--platform=android-8 \
–install-dir=/MYDEV/android=9-toolchain
$ export PATH=/MYDEV/android=9-toolchain/bin:$PATH

샘플 코드 컴파일 방법
test.cpp 가 있다고 가정하고

1
$ arm-linux-androideabi-g++ -o test_arm test.cpp

Makefile 을 다음과 같이 만든다.

1
2
3
4
5
6
7
8
9
10
ARM_COMPILE = arm-linux-androideabi-
CC = g++

ARM_CC = $(ARM_COMPILE)g++
ARM_INCLUDES = -I /MYDEV/android=9-toolchain/sysroot/usr/include
CFLAGS = -O2 -Wall -D_LINUX -fno-strict-aliasing -D_COLOR_LOG
BINS = test

arm:
$(ARM_CC) $(CFLAGS) -o test_arm test.cpp $(ARM_INCLUDES)

ffmpeg build

standalone toolchain을 사용한다.

ffmpeg configuration

1
export ANDROID_ROOT=/cygdrive/c/my-android-toolchain
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ANDROID_ROOT=/home/qkboo/my-android-toolchain \
./configure --target-os=linux \
--arch=arm \
--enable-cross-compile \
--cc=$ANDROID_ROOT/bin/arm-linux-androideabi-gcc \
--cross-prefix=$ANDROID_ROOT/bin/arm-linux-androideabi- \
--extra-cflags="-marm -march=armv7-a -mfloat-abi=softfp -mfpu=neon" \
--extra-ldflags="-Wl,--fix-cortex-a8" \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-avdevice \
--disable-network \
--disable-devices \
--disable-filters

맨 첫 줄의 ANDROID_ROOT 값은 자신이 standalone toolchain을 설치한 폴더로 수정합니다.

참고로

  • “–arch=arm”과 “–enable-cross-compile”: arm CPU 용으로 cross compile 하겠다는 옵션입니다.
  • “–cc”나 “–cross-prefix”: cross compile 할 때 사용할 compiler에 관한 정보를 줍니다.
  • “–extra-cflags”나 “–extra-ldflags”는 neon 사용할 때 쓰는 옵션입니다. (c:/android-ndk-r5b/docs/STANDALONE-TOOLCHAIN.html 참조)

나머지는 ffmpeg에서 이러이러한 기능은 빼고 컴파일 하겠다는 뜻입니다. 예를들어 network 이런 기능은 필요없겠지요?

생성된 config.h 파일을 열어봅니다.

1
2
3
4
5
6
7
8
9
10
11
#define ARCH_ARM 1

#define HAVE_ARMV5TE 1

#define HAVE_ARMV6 1

#define HAVE_ARMV6T2 1

#define HAVE_ARMVFP 1

#define HAVE_NEON 1

위와 같은 설정들이 잘 되어 있음을 확인할 수 있으실 겁니다.

config.h 파일에서 #define restrict restrict 부분을 찾아 다음과 같이 바꾼다.

1
#define restrict

X264 컴파일

http://bongjaemoon.wordpress.com/2012/05/25/ffmpeg-x264-compile-for-using-with-android-ndk-on-mac-osx/

Application.mk 작성

g:/Root/FFmpegBasic/jni 폴더에 Application.mk 파일을 만듭니다.
내용은 간단히 아래와 같이 한 줄만 작성합니다.

  1. APP_ABI := armeabi-v7a

참고:
arm architecture ARMv7-A 이상을 타겟으로 컴파일 하겠다는 옵션입니다.
arm CoretexA8 이상의 core가 이에 해당됩니다.
앞서 말씀드린대로 arm11 코어를 사용한 Optimus One, Galaxy Neo 같은 폰에서는 안 돌아가겠지요.

Android.mk 작성

http://www.viper.pe.kr/docs/make-ko/make-ko_toc.html (한글)
http://sunsite.ualberta.ca/Documentation/Gnu/make-3.79/html_chapter/make_toc.html (영문)

Android.mk 는 폴더마다 여러개를 작성해야 합니다.공통으로 사용할 common.mk 파일을 먼저 작성한 후, 각각 폴더마다 설명하겠습니다.

  • common.mk

g:/Root/FFmpegBasic/jni/ffmpeg 폴더에 common.mk 파일을 만듭니다.모든 Android.mk에서 공통으로 include 해서 사용할 파일입니다.

common.mk에서는 크게 두가지 일을 할 것입니다.1) 공통으로 사용할 컴파일 옵션을 정의합니다.2) configure를 통해 생성된 파일에서 컴파일 할 소스 파일 이름들을 읽어 저장합니다.

  1. 컴파일 옵션은 다음과 같이 한 줄이면 됩니다.

1.COMMON_CFLAGS := -DHAVE_AV_CONFIG_H -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -DPIC -std=c99 -fomit-frame-pointer -fPIC -fno-math-errno -fno-signed-zeros -fno-tree-vectorize
참고:컴파일 옵션이 복잡해 보이지만 그냥 configure에서 생성된 컴파일 옵션을 그대로 정리해 준 것 뿐입니다.

ffmpeg 폴더의 common.mak 파일을 열어보시면아래와 같은 부분이 있습니다.
1.%.o: %.c 2.$(CCDEP)
3.$(CC) $(CPPFLAGS) $(CFLAGS) $(CC_DEPFLAGS) -c $(CC_O) $<
FFmpeg 컴파일 할 때, $(CPPFLAGS) $(CFLAGS) $(CC_DEPFLAGS) 이 세 개의 매크로에 정의된 옵션들을 사용하는 것을 알 수 있습니다.

ffmpeg 폴더의 config.mak 파일을 열어보시면 이 값들이 정의되어 있습니다.

CPPFLAGS는 아래와 같습니다.
1.CPPFLAGS= -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -DPIC
이 값들은 다 사용해 줍니다.

CFLAGS는 엄청 깁니다.
1.CFLAGS= -marm -march=armv7-a -mfloat-abi=softfp -mfpu=neon  -std=c99 -fomit-frame-pointer -fPIC -marm -g -Wdeclaration-after-statement -Wall -Wno-parentheses -Wno-switch -Wdisabled-optimization -Wpointer-arith -Wredundant-decls -Wno-pointer-sign -Wcast-qual -Wwrite-strings -Wtype-limits -Wundef -Wmissing-prototypes -Wno-pointer-to-int-cast -O3 -fno-math-errno -fno-signed-zeros -fno-tree-vectorize -Werror=implicit-function-declaration -Werror=missing-prototypes
복잡해 보이지만 하나씩 차근히 보면 정리가 됩니다.
여기서 -marm -march=armv7-a -mfloat-abi=softfp -mfpu=neon -g -O3 옵션들은 다 뺍니다.우리는 Android ndk-build를 사용할 것이기 때문에 -O3 같은 최적화 관련 옵션은 지정하지 않습니다.(이것은 android build system이 알아서 해줍니다)-marm -march=armv7-a -mfloat-abi=softfp -mfpu=neon 이와 같은 cross compile관련, neon 관련 옵션도 빼줍니다.(이것은 나중에 Android.mk의 옵션으로 지정해 줄 것입니다)마지막으로 -W 로 시작하는 옵션은 warning 관련 옵션이니 그냥 다 뺍니다.

CC_DEPFLAGS는 별 것 없고 상관없는 값들입니다. 무시합니다.

추가로 subdir.mak 파일을 보시면 아래와 같은 부분이 있습니다. 1.$(OBJS) $(SUBDIR)%.ho $(SUBDIR)%-test.o $(TESTOBJS): CPPFLAGS += -DHAVE_AV_CONFIG_H
$(OBJS) 에 정의된 모든 파일에 위 조건이 해당되므로 -DHAVE_AV_CONFIG_H 도 포함합니다.

이렇게 정리하면 위에서 한 줄로 정리한 COMMON_CFLAGS 컴파일 옵션들이 나옵니다.

  1. 컴파일 할 소스 파일들을 정의

이 부분은 소스가 좀 길고 복잡하게 느껴질 수 있습니다. 하지만 역시 핵심은 간단합니다.

먼저 FFmpeg의 Makefile을 하나만 분석해 보겠습니다.
ffmpeg 폴더의 common.mak 파일을 열어보면 아래와 같은 부분이 있습니다.
1.OBJS      += $(OBJS-yes)
컴파일에 사용할 소스 파일은 OBJS 매크로와 OBJS-yes 매크로에 정의되어 있다는 것을 알 수 있습니다.
우리도 이 소스들을 컴파일 하면 되므로 똑같이 적어줍니다.

이제 OBJS 매크로에는 xxxxx.o 와 같은 object 파일들이 쭉 저장되게 됩니다.이걸 그냥 간단히 전부 xxxxx.c로 변환해서 쓰면 가장 쉽겠지만 그렇게 간단하지는 않습니다.우선 c 파일 외에도 xxxxx.S 와 같은 어셈블리 코드들이 포함되어 있고,neon 컴파일 해야하는 소스들은 xxxxx.c.neon 또는 xxxxx.S.neon 과 같이 neon 접미사를 붙여줘야 하기 때문입니다.

다행인 것은, FFmpeg 소스들을 보면 neon 컴파일 해야 하는 소스들은 모두
_neon.c 와 같이 _neon 접미사가 붙어 있어서 이것으로 구분이 가능합니다.(ffmpeg/libavcodec/arm 폴더의 파일들을 훑어 보시기 바랍니다)따라서 _neon 접미사를 검색해서 해당 접미사가 있는 소스에만 .neon을 마지막에 추가해 주면 됩니다.

위와 같은 과정을 수동으로 일일이 진행하셔도 좋지만 번거로우니 Makefile 문법을 사용해 작성해 주면 됩니다.최종적으로 컴파일 할 소스 파일들은 각각 다음 매크로에 저장할 것입니다.

C_FILES: 컴파일 할 c 파일S_FILES: 컴파일 할 S 파일NEON_C_FILES: neon 컴파일 할 c 파일NEON_S_FILES: neon 컴파일 할 S 파일FFFILES: 컴파일 할 모든 소스 파일 전부 정의

이제까지 설명한 것을 종합해서 common.mk의 전체 소스를 보여드리면 아래와 같습니다.
common.mk 파일을 다음과 같이 작성해줍니다.

01.COMMON_CFLAGS := -DHAVE_AV_CONFIG_H -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -DPIC -std=c99 -fomit-frame-pointer -fPIC -fno-math-errno -fno-signed-zeros -fno-tree-vectorize
02. 
03.OBJS += $(OBJS-yes)
04. 
05.ALL_S_FILES := $(wildcard $(LOCAL_PATH)/$(ARCH)/.S)
06.ALL_S_FILES := $(addprefix $(ARCH)/,$(notdir $(ALL_S_FILES)))
07. 
08.NEON_S_FILES := $(wildcard $(LOCAL_PATH)/$(ARCH)/
_neon.S)
09.NEON_S_FILES := $(addprefix $(ARCH)/,$(notdir $(NEON_S_FILES)))
10. 
11.NEON_C_FILES := $(wildcard $(LOCAL_PATH)/$(ARCH)/*_neon.c)
12.NEON_C_FILES := $(addprefix $(ARCH)/,$(notdir $(NEON_C_FILES)))
13. 
14.S_FILES := $(filter-out $(NEON_S_FILES),$(ALL_S_FILES))
15. 
16.C_OBJS := $(OBJS)
17.ifneq ($(S_FILES),)
18.S_OBJS := $(S_FILES:.S=.o)
19.S_OBJS := $(filter $(S_OBJS),$(C_OBJS))
20.C_OBJS := $(filter-out $(S_OBJS),$(C_OBJS))
21.else
22.S_OBJS :=
23.endif
24. 
25.ifneq ($(NEON_S_FILES),)
26.NEON_S_OBJS := $(NEON_S_FILES:.S=.o)
27.NEON_S_OBJS := $(filter $(NEON_S_OBJS),$(C_OBJS))
28.C_OBJS := $(filter-out $(NEON_S_OBJS),$(C_OBJS))
29.else
30.NEON_S_OBJS :=
31.endif
32. 
33.ifneq ($(NEON_C_FILES),)
34.NEON_C_OBJS := $(NEON_C_FILES:.c=.o)
35.NEON_C_OBJS := $(filter $(NEON_C_OBJS),$(C_OBJS))
36.C_OBJS := $(filter-out $(NEON_C_OBJS),$(C_OBJS))
37.else
38.NEON_C_OBJS :=
39.endif
40. 
41.C_FILES := $(C_OBJS:.o=.c)
42.S_FILES := $(S_OBJS:.o=.S)
43.NEON_C_FILES := $(NEON_C_OBJS:.o=.c.neon)
44.NEON_S_FILES := $(NEON_S_OBJS:.o=.S.neon)
45. 
46.FFFILES := $(sort $(NEON_S_FILES)) $(sort $(NEON_C_FILES)) $(sort $(S_FILES)) $(sort $(C_FILES))

참고:OBJS 와 OBJS-yes 매크로가 어떻게 생성되는지 보겠습니다.

ffmpeg/libavcodec 폴더의 Makefile을 열어 봅니다.
1.OBJS = allcodecs.o                                                     
2.audioconvert.o                                                  
3.avpacket.o                                                      
4.bitstream.o                                                     
5.bitstream_filter.o                                              
6.dsputil.o                                                       
위와 같은 소스를 볼 수 있습니다.이는 다시 말하면 allcodecs.c, audioconvert.c … 와 같은 소스들은 컴파일 옵션과 상관없이 무조건 컴파일 하겠다는 뜻입니다.

다음으로 아래와 같은 코드들이 이어집니다.
1.OBJS-$(CONFIG_AANDCT)                  += aandcttab.o
2.OBJS-$(CONFIG_AC3DSP)                  += ac3dsp.o
3.OBJS-$(CONFIG_CRYSTALHD)               += crystalhd.o
ffmpeg 폴더의 config.mak 파일을 열어서 CONFIG_AANDCT, CONFIG_CRYSTALHD 등을 찾아 보시면 이게 어떻게 돌아가는지 알 수 있습니다.config.mak 파일을 열어 보면 아래와 같이 되어 있습니다.
1.CONFIG_AANDCT=yes
2.!CONFIG_CRYSTALHD=yes
즉, “OBJS-$(CONFIG_AANDCT)”는 “OBJS-yes”로 변환되어 aandcttab.c 는 컴파일할 것이고,”OBJS-$(CONFIG_CRYSTALHD)”는 그렇지 않으니 crystalhd.c 는 컴파일 하지 않을 것 입니다.

이런 방법은 거의 모든 open source library에서 사용하고 있는 표준적인 방법이니 익숙해지는 것이 좋습니다.

참조

[^1]: Compiling ffmeg on macOS