1#!/bin/bash -e
2#
3# Copyright (c) 2012 The Chromium Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7# This script is used to generate .gypi files and files in the config/platform
8# directories needed to build libvpx.
9# Every time libvpx source code is updated just run this script.
10#
11# For example:
12# $ ./generate_gypi.sh
13#
14# And this will update all the .gypi and config files needed.
15#
16# !!! It's highly recommended to install yasm before running this script.
17
18export LC_ALL=C
19BASE_DIR=`pwd`
20LIBVPX_SRC_DIR="source/libvpx"
21LIBVPX_CONFIG_DIR="source/config"
22
23# Print gypi boilerplate header
24# $1 - Output base name
25function write_gypi_header {
26  echo "# This file is generated. Do not edit." > $1
27  echo "# Copyright (c) 2013 The Chromium Authors. All rights reserved." >> $1
28  echo "# Use of this source code is governed by a BSD-style license that can be" >> $1
29  echo "# found in the LICENSE file." >> $1
30  echo "" >> $1
31  echo "{" >> $1
32}
33
34# Print gypi boilerplate footer
35# $1 - Output base name
36function write_gypi_footer {
37  echo "}" >> $1
38}
39
40# Generate a gypi with a list of source files.
41# $1 - Array name for file list. This is processed with 'declare' below to
42#      regenerate the array locally.
43# $2 - Output file
44function write_file_list {
45  # Convert the first argument back in to an array.
46  declare -a file_list=("${!1}")
47
48  write_gypi_header $2
49
50  echo "  'sources': [" >> $2
51  for f in $file_list
52  do
53    echo "    '<(libvpx_source)/$f'," >> $2
54  done
55  echo "  ]," >> $2
56
57  write_gypi_footer $2
58}
59
60# Target template function
61# $1 - Array name for file list.
62# $2 - Output file
63# $3 - Target name
64# $4 - Compiler flag
65function write_target_definition {
66  declare -a sources_list=("${!1}")
67
68  echo "    {" >> $2
69  echo "      'target_name': '$3'," >> $2
70  echo "      'type': 'static_library'," >> $2
71  echo "      'include_dirs': [" >> $2
72  echo "        'source/config/<(OS_CATEGORY)/<(target_arch_full)'," >> $2
73  echo "        '<(libvpx_source)'," >> $2
74  echo "      ]," >> $2
75  echo "      'sources': [" >> $2
76  for f in $sources_list
77  do
78    echo "        '<(libvpx_source)/$f'," >> $2
79  done
80  echo "      ]," >> $2
81  echo "      'conditions': [" >> $2
82  echo "        ['os_posix==1 and OS!=\"mac\" and OS!=\"ios\"', {" >> $2
83  echo "          'cflags!': [ '-mfpu=vfpv3-d16' ]," >> $2
84  echo "          'cflags': [ '-m$4', ]," >> $2
85  echo "        }]," >> $2
86  echo "        ['OS==\"mac\" or OS==\"ios\"', {" >> $2
87  echo "          'xcode_settings': {" >> $2
88  echo "            'OTHER_CFLAGS': [ '-m$4', ]," >> $2
89  echo "          }," >> $2
90  echo "        }]," >> $2
91  if [[ $4 == avx* ]]; then
92  echo "        ['OS==\"win\"', {" >> $2
93  echo "          'msvs_settings': {" >> $2
94  echo "            'VCCLCompilerTool': {" >> $2
95  echo "              'EnableEnhancedInstructionSet': '3', # /arch:AVX" >> $2
96  echo "            }," >> $2
97  echo "          }," >> $2
98  echo "        }]," >> $2
99  fi
100  echo "      ]," >> $2
101  echo "    }," >> $2
102}
103
104
105# Generate a gypi which applies additional compiler flags based on the file
106# name.
107# $1 - Array name for file list.
108# $2 - Output file
109function write_special_flags {
110  declare -a file_list=("${!1}")
111
112  local mmx_sources=$(echo "$file_list" | grep '_mmx\.c$')
113  local sse2_sources=$(echo "$file_list" | grep '_sse2\.c$')
114  local sse3_sources=$(echo "$file_list" | grep '_sse3\.c$')
115  local ssse3_sources=$(echo "$file_list" | grep '_ssse3\.c$')
116  local sse4_1_sources=$(echo "$file_list" | grep '_sse4\.c$')
117  local avx_sources=$(echo "$file_list" | grep '_avx\.c$')
118  local avx2_sources=$(echo "$file_list" | grep '_avx2\.c$')
119
120  local neon_sources=$(echo "$file_list" | grep '_neon\.c$')
121
122  # Intrinsic functions and files are in flux. We can selectively generate them
123  # but we can not selectively include them in libvpx.gyp. Throw some errors
124  # when new targets are needed.
125
126  write_gypi_header $2
127
128  echo "  'targets': [" >> $2
129
130  # x86[_64]
131  if [ 0 -ne ${#mmx_sources} ]; then
132    write_target_definition mmx_sources[@] $2 libvpx_intrinsics_mmx mmx
133  fi
134  if [ 0 -ne ${#sse2_sources} ]; then
135    write_target_definition sse2_sources[@] $2 libvpx_intrinsics_sse2 sse2
136  fi
137  if [ 0 -ne ${#sse3_sources} ]; then
138    #write_target_definition sse3_sources[@] $2 libvpx_intrinsics_sse3 sse3
139    echo "ERROR: Uncomment sse3 sections in libvpx.gyp"
140    exit 1
141  fi
142  if [ 0 -ne ${#ssse3_sources} ]; then
143    write_target_definition ssse3_sources[@] $2 libvpx_intrinsics_ssse3 ssse3
144  fi
145  if [ 0 -ne ${#sse4_1_sources} ]; then
146    #write_target_definition sse4_1_sources[@] $2 libvpx_intrinsics_sse4_1 sse4.1
147    echo "ERROR: Uncomment sse4_1 sections in libvpx.gyp"
148    exit 1
149  fi
150  if [ 0 -ne ${#avx_sources} ]; then
151    #write_target_definition avx_sources[@] $2 libvpx_intrinsics_avx avx
152    echo "ERROR: Uncomment avx sections in libvpx.gyp"
153    exit 1
154  fi
155  if [ 0 -ne ${#avx2_sources} ]; then
156    #write_target_definition avx2_sources[@] $2 libvpx_intrinsics_avx2 avx2
157    echo "ERROR: Uncomment avx2 sections in libvpx.gyp"
158    exit 1
159  fi
160
161  # arm neon
162  if [ 0 -ne ${#neon_sources} ]; then
163    write_target_definition neon_sources[@] $2 libvpx_intrinsics_neon fpu=neon
164  fi
165
166  echo "  ]," >> $2
167
168  write_gypi_footer $2
169}
170
171# Convert a list of source files into gypi file.
172# $1 - Input file.
173# $2 - Output gypi file base. Will generate additional .gypi files when
174#      different compilation flags are required.
175function convert_srcs_to_gypi {
176  # Do the following here:
177  # 1. Filter .c, .h, .s, .S and .asm files.
178  # 2. Move certain files to a separate include to allow applying different
179  #    compiler options.
180  # 3. Replace .asm.s to .asm because gyp will do the conversion.
181
182  local source_list=$(grep -E '(\.c|\.h|\.S|\.s|\.asm)$' $1)
183
184  # _offsets are used in pre-processing to generate files for assembly. They are
185  # not part of the compiled library.
186  source_list=$(echo "$source_list" | grep -v '_offsets\.c')
187
188  # Not sure why vpx_config is not included.
189  source_list=$(echo "$source_list" | grep -v 'vpx_config\.c')
190
191  # The actual ARM files end in .asm. We have rules to translate them to .S
192  source_list=$(echo "$source_list" | sed s/\.asm\.s$/.asm/)
193
194  # Select all x86 files ending with .c
195  local intrinsic_list=$(echo "$source_list" | \
196    egrep 'vp[89]/(encoder|decoder|common)/x86/'  | \
197    egrep '(mmx|sse2|sse3|ssse3|sse4|avx|avx2).c$')
198
199  # Select all neon files ending in C but only when building in RTCD mode
200  if [ "libvpx_srcs_arm_neon_cpu_detect" == "$2" ]; then
201    # Select all arm neon files ending in _neon.c
202    # the pattern may need to be updated if vpx_scale gets intrinics
203    local intrinsic_list=$(echo "$source_list" | \
204      egrep 'vp[89]/(encoder|decoder|common)/arm/neon/'  | \
205      egrep '_neon.c$')
206  fi
207
208  # Remove these files from the main list.
209  source_list=$(comm -23 <(echo "$source_list") <(echo "$intrinsic_list"))
210
211  write_file_list source_list $BASE_DIR/$2.gypi
212
213  # All the files are in a single "element." Check if the first element has
214  # length 0.
215  if [ 0 -ne ${#intrinsic_list} ]; then
216    write_special_flags intrinsic_list[@] $BASE_DIR/$2_intrinsics.gypi
217  fi
218
219}
220
221# Clean files from previous make.
222function make_clean {
223  make clean > /dev/null
224  rm -f libvpx_srcs.txt
225}
226
227# Lint a pair of vpx_config.h and vpx_config.asm to make sure they match.
228# $1 - Header file directory.
229function lint_config {
230  # mips does not contain any assembly so the header does not need to be
231  # compared to the asm.
232  if [[ "$1" != *mipsel ]]; then
233    $BASE_DIR/lint_config.sh \
234      -h $BASE_DIR/$LIBVPX_CONFIG_DIR/$1/vpx_config.h \
235      -a $BASE_DIR/$LIBVPX_CONFIG_DIR/$1/vpx_config.asm
236  fi
237}
238
239# Print the configuration.
240# $1 - Header file directory.
241function print_config {
242  $BASE_DIR/lint_config.sh -p \
243    -h $BASE_DIR/$LIBVPX_CONFIG_DIR/$1/vpx_config.h \
244    -a $BASE_DIR/$LIBVPX_CONFIG_DIR/$1/vpx_config.asm
245}
246
247# Print the configuration from Header file.
248# This function is an abridged version of print_config which does not use
249# lint_config and it does not require existence of vpx_config.asm.
250# $1 - Header file directory.
251function print_config_basic {
252  combined_config="$(cat $BASE_DIR/$LIBVPX_CONFIG_DIR/$1/vpx_config.h \
253                   | grep -E ' +[01] *$')"
254  combined_config="$(echo "$combined_config" | grep -v DO1STROUNDING)"
255  combined_config="$(echo "$combined_config" | sed 's/[ \t]//g')"
256  combined_config="$(echo "$combined_config" | sed 's/.*define//')"
257  combined_config="$(echo "$combined_config" | sed 's/0$/=no/')"
258  combined_config="$(echo "$combined_config" | sed 's/1$/=yes/')"
259  echo "$combined_config" | sort | uniq
260}
261
262# Generate *_rtcd.h files.
263# $1 - Header file directory.
264# $2 - Architecture.
265function gen_rtcd_header {
266  echo "Generate $LIBVPX_CONFIG_DIR/$1/*_rtcd.h files."
267
268  rm -rf $BASE_DIR/$TEMP_DIR/libvpx.config
269  if [ "$2" = "mipsel" ]; then
270    print_config_basic $1 > $BASE_DIR/$TEMP_DIR/libvpx.config
271  else
272    $BASE_DIR/lint_config.sh -p \
273      -h $BASE_DIR/$LIBVPX_CONFIG_DIR/$1/vpx_config.h \
274      -a $BASE_DIR/$LIBVPX_CONFIG_DIR/$1/vpx_config.asm \
275      -o $BASE_DIR/$TEMP_DIR/libvpx.config
276  fi
277
278  $BASE_DIR/$LIBVPX_SRC_DIR/build/make/rtcd.pl \
279    --arch=$2 \
280    --sym=vp8_rtcd \
281    --config=$BASE_DIR/$TEMP_DIR/libvpx.config \
282    --disable-avx2 \
283    $BASE_DIR/$LIBVPX_SRC_DIR/vp8/common/rtcd_defs.pl \
284    > $BASE_DIR/$LIBVPX_CONFIG_DIR/$1/vp8_rtcd.h
285
286  $BASE_DIR/$LIBVPX_SRC_DIR/build/make/rtcd.pl \
287    --arch=$2 \
288    --sym=vp9_rtcd \
289    --config=$BASE_DIR/$TEMP_DIR/libvpx.config \
290    --disable-avx2 \
291    $BASE_DIR/$LIBVPX_SRC_DIR/vp9/common/vp9_rtcd_defs.pl \
292    > $BASE_DIR/$LIBVPX_CONFIG_DIR/$1/vp9_rtcd.h
293
294  $BASE_DIR/$LIBVPX_SRC_DIR/build/make/rtcd.pl \
295    --arch=$2 \
296    --sym=vpx_scale_rtcd \
297    --config=$BASE_DIR/$TEMP_DIR/libvpx.config \
298    --disable-avx2 \
299    $BASE_DIR/$LIBVPX_SRC_DIR/vpx_scale/vpx_scale_rtcd.pl \
300    > $BASE_DIR/$LIBVPX_CONFIG_DIR/$1/vpx_scale_rtcd.h
301
302  rm -rf $BASE_DIR/$TEMP_DIR/libvpx.config
303}
304
305# Generate Config files. "--enable-external-build" must be set to skip
306# detection of capabilities on specific targets.
307# $1 - Header file directory.
308# $2 - Config command line.
309function gen_config_files {
310  ./configure $2  > /dev/null
311
312  # Generate vpx_config.asm. Do not create one for mips.
313  if [[ "$1" != *mipsel ]]; then
314    if [[ "$1" == *x64* ]] || [[ "$1" == *ia32* ]]; then
315      egrep "#define [A-Z0-9_]+ [01]" vpx_config.h | awk '{print $2 " equ " $3}' > vpx_config.asm
316    else
317      egrep "#define [A-Z0-9_]+ [01]" vpx_config.h | awk '{print $2 " EQU " $3}' | perl $BASE_DIR/$LIBVPX_SRC_DIR/build/make/ads2gas.pl > vpx_config.asm
318    fi
319  fi
320
321  cp vpx_config.* $BASE_DIR/$LIBVPX_CONFIG_DIR/$1
322  make_clean
323  rm -rf vpx_config.*
324}
325
326echo "Create temporary directory."
327TEMP_DIR="$LIBVPX_SRC_DIR.temp"
328rm -rf $TEMP_DIR
329cp -R $LIBVPX_SRC_DIR $TEMP_DIR
330cd $TEMP_DIR
331
332echo "Generate Config Files"
333# TODO(joeyparrish) Enable AVX2 when broader VS2013 support is available
334all_platforms="--enable-external-build --enable-postproc --disable-install-srcs --enable-multi-res-encoding --enable-temporal-denoising --disable-unit-tests --disable-install-docs --disable-examples --disable-avx2"
335gen_config_files linux/ia32 "--target=x86-linux-gcc --disable-ccache --enable-pic --enable-realtime-only ${all_platforms}"
336gen_config_files linux/x64 "--target=x86_64-linux-gcc --disable-ccache --enable-pic --enable-realtime-only ${all_platforms}"
337gen_config_files linux/arm "--target=armv6-linux-gcc --enable-pic --enable-realtime-only --disable-install-bins --disable-install-libs --disable-edsp ${all_platforms}"
338gen_config_files linux/arm-neon "--target=armv7-linux-gcc --enable-pic --enable-realtime-only --disable-edsp ${all_platforms}"
339gen_config_files linux/arm-neon-cpu-detect "--target=armv7-linux-gcc --enable-pic --enable-realtime-only --enable-runtime-cpu-detect --disable-edsp ${all_platforms}"
340gen_config_files linux/arm64 "--force-target=armv8-linux-gcc --enable-pic --enable-realtime-only --disable-edsp ${all_platforms}"
341gen_config_files linux/mipsel "--target=mips32-linux-gcc --disable-fast-unaligned ${all_platforms}"
342gen_config_files linux/generic "--target=generic-gnu --enable-pic --enable-realtime-only ${all_platforms}"
343gen_config_files win/ia32 "--target=x86-win32-vs12 --enable-realtime-only ${all_platforms}"
344gen_config_files win/x64 "--target=x86_64-win64-vs12 --enable-realtime-only ${all_platforms}"
345gen_config_files mac/ia32 "--target=x86-darwin9-gcc --enable-pic --enable-realtime-only ${all_platforms}"
346gen_config_files mac/x64 "--target=x86_64-darwin9-gcc --enable-pic --enable-realtime-only ${all_platforms}"
347gen_config_files nacl "--target=generic-gnu --enable-pic --enable-realtime-only ${all_platforms}"
348
349echo "Remove temporary directory."
350cd $BASE_DIR
351rm -rf $TEMP_DIR
352
353echo "Lint libvpx configuration."
354lint_config linux/ia32
355lint_config linux/x64
356lint_config linux/arm
357lint_config linux/arm-neon
358lint_config linux/arm-neon-cpu-detect
359lint_config linux/arm64
360lint_config linux/mipsel
361lint_config linux/generic
362lint_config win/ia32
363lint_config win/x64
364lint_config mac/ia32
365lint_config mac/x64
366lint_config nacl
367
368echo "Create temporary directory."
369TEMP_DIR="$LIBVPX_SRC_DIR.temp"
370rm -rf $TEMP_DIR
371cp -R $LIBVPX_SRC_DIR $TEMP_DIR
372cd $TEMP_DIR
373
374gen_rtcd_header linux/ia32 x86
375gen_rtcd_header linux/x64 x86_64
376gen_rtcd_header linux/arm armv6
377gen_rtcd_header linux/arm-neon armv7
378gen_rtcd_header linux/arm-neon-cpu-detect armv7
379gen_rtcd_header linux/arm64 armv8
380gen_rtcd_header linux/mipsel mipsel
381gen_rtcd_header linux/generic generic
382gen_rtcd_header win/ia32 x86
383gen_rtcd_header win/x64 x86_64
384gen_rtcd_header mac/ia32 x86
385gen_rtcd_header mac/x64 x86_64
386gen_rtcd_header nacl nacl
387
388echo "Prepare Makefile."
389./configure --target=generic-gnu > /dev/null
390make_clean
391
392echo "Generate X86 source list."
393config=$(print_config linux/ia32)
394make_clean
395make libvpx_srcs.txt target=libs $config > /dev/null
396convert_srcs_to_gypi libvpx_srcs.txt libvpx_srcs_x86
397
398# Copy vpx_version.h. The file should be the same for all platforms.
399cp vpx_version.h $BASE_DIR/$LIBVPX_CONFIG_DIR
400
401echo "Generate X86_64 source list."
402config=$(print_config linux/x64)
403make_clean
404make libvpx_srcs.txt target=libs $config > /dev/null
405convert_srcs_to_gypi libvpx_srcs.txt libvpx_srcs_x86_64
406
407echo "Generate ARM source list."
408config=$(print_config linux/arm)
409make_clean
410make libvpx_srcs.txt target=libs $config > /dev/null
411convert_srcs_to_gypi libvpx_srcs.txt libvpx_srcs_arm
412
413echo "Generate ARM NEON source list."
414config=$(print_config linux/arm-neon)
415make_clean
416make libvpx_srcs.txt target=libs $config > /dev/null
417convert_srcs_to_gypi libvpx_srcs.txt libvpx_srcs_arm_neon
418
419echo "Generate ARM NEON CPU DETECT source list."
420config=$(print_config linux/arm-neon-cpu-detect)
421make_clean
422make libvpx_srcs.txt target=libs $config > /dev/null
423convert_srcs_to_gypi libvpx_srcs.txt libvpx_srcs_arm_neon_cpu_detect
424
425echo "Generate ARM64 source list."
426config=$(print_config linux/arm64)
427make_clean
428make libvpx_srcs.txt target=libs $config > /dev/null
429convert_srcs_to_gypi libvpx_srcs.txt libvpx_srcs_arm64
430
431echo "Generate MIPS source list."
432config=$(print_config_basic linux/mipsel)
433make_clean
434make libvpx_srcs.txt target=libs $config > /dev/null
435convert_srcs_to_gypi libvpx_srcs.txt libvpx_srcs_mips
436
437echo "Generate NaCl source list."
438config=$(print_config_basic nacl)
439make_clean
440make libvpx_srcs.txt target=libs $config > /dev/null
441convert_srcs_to_gypi libvpx_srcs.txt libvpx_srcs_nacl
442
443echo "Generate GENERIC source list."
444config=$(print_config_basic linux/generic)
445make_clean
446make libvpx_srcs.txt target=libs $config > /dev/null
447convert_srcs_to_gypi libvpx_srcs.txt libvpx_srcs_generic
448
449echo "Remove temporary directory."
450cd $BASE_DIR
451rm -rf $TEMP_DIR
452
453# TODO(fgalligan): Is "--disable-fast-unaligned" needed on mipsel?
454# TODO(fgalligan): Can we turn on "--enable-realtime-only" for mipsel?
455