build-protoc.sh 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. #!/bin/bash
  2. # Builds protoc executable into target/<OS>/<ARCH>/protoc.exe; optionally builds
  3. # protoc plugins into target/<OS>/<ARCH>/protoc-gen-*.exe
  4. #
  5. # Usage: ./build-protoc.sh <OS> <ARCH> <TARGET>
  6. #
  7. # <TARGET> can be "protoc" or "protoc-gen-javalite". Supported <OS> <ARCH>
  8. # combinations:
  9. # HOST <OS> <ARCH> <COMMENT>
  10. # cygwin windows x86_32 Requires: i686-w64-mingw32-gcc
  11. # cygwin windows x86_64 Requires: x86_64-w64-mingw32-gcc
  12. # linux linux aarch_64 Requires: g++-aarch64-linux-gnu
  13. # linux linux x86_32
  14. # linux linux x86_64
  15. # linux windows x86_32 Requires: i686-w64-mingw32-gcc
  16. # linux windows x86_64 Requires: x86_64-w64-mingw32-gcc
  17. # macos osx x86_32
  18. # macos osx x86_64
  19. # mingw windows x86_32
  20. # mingw windows x86_64
  21. #
  22. # Before running this script, make sure you have generated the configure script
  23. # in the parent directory (i.e., run ./autogen.sh there).
  24. OS=$1
  25. ARCH=$2
  26. MAKE_TARGET=$3
  27. if [[ $# < 3 ]]; then
  28. echo "Not enough arguments provided."
  29. exit 1
  30. fi
  31. case $MAKE_TARGET in
  32. protoc-gen-javalite)
  33. ;;
  34. protoc)
  35. ;;
  36. *)
  37. echo "Target ""$MAKE_TARGET"" invalid."
  38. exit 1
  39. esac
  40. # Under Cygwin, bash doesn't have these in PATH when called from Maven which
  41. # runs in Windows version of Java.
  42. export PATH="/bin:/usr/bin:$PATH"
  43. ############################################################################
  44. # Helper functions
  45. ############################################################################
  46. E_PARAM_ERR=98
  47. E_ASSERT_FAILED=99
  48. # Usage:
  49. fail()
  50. {
  51. echo "ERROR: $1"
  52. echo
  53. exit $E_ASSERT_FAILED
  54. }
  55. # Usage: assertEq VAL1 VAL2 $LINENO
  56. assertEq ()
  57. {
  58. lineno=$3
  59. if [ -z "$lineno" ]; then
  60. echo "lineno not given"
  61. exit $E_PARAM_ERR
  62. fi
  63. if [[ "$1" != "$2" ]]; then
  64. echo "Assertion failed: \"$1\" == \"$2\""
  65. echo "File \"$0\", line $lineno" # Give name of file and line number.
  66. exit $E_ASSERT_FAILED
  67. fi
  68. }
  69. # Checks the artifact is for the expected architecture
  70. # Usage: checkArch <path-to-protoc>
  71. checkArch ()
  72. {
  73. echo
  74. echo "Checking file format ..."
  75. if [[ "$OS" == windows || "$OS" == linux ]]; then
  76. format="$(objdump -f "$1" | grep -o "file format .*$" | grep -o "[^ ]*$")"
  77. echo Format=$format
  78. if [[ "$OS" == linux ]]; then
  79. host_machine="$(uname -m)";
  80. if [[ "$ARCH" == x86_32 ]]; then
  81. assertEq $format "elf32-i386" $LINENO
  82. elif [[ "$ARCH" == x86_64 ]]; then
  83. assertEq $format "elf64-x86-64" $LINENO
  84. elif [[ "$ARCH" == aarch_64 ]]; then
  85. assertEq $format "elf64-little" $LINENO
  86. elif [[ "$ARCH" == s390_64 ]]; then
  87. if [[ $host_machine == s390x ]];then
  88. assertEq $format "elf64-s390" $LINENO
  89. else
  90. assertEq $format "elf64-big" $LINENO
  91. fi
  92. elif [[ "$ARCH" == ppcle_64 ]]; then
  93. if [[ $host_machine == ppc64le ]];then
  94. assertEq $format "elf64-powerpcle" $LINENO
  95. else
  96. assertEq $format "elf64-little" $LINENO
  97. fi
  98. else
  99. fail "Unsupported arch: $ARCH"
  100. fi
  101. else
  102. # $OS == windows
  103. if [[ "$ARCH" == x86_32 ]]; then
  104. assertEq $format "pei-i386" $LINENO
  105. elif [[ "$ARCH" == x86_64 ]]; then
  106. assertEq $format "pei-x86-64" $LINENO
  107. else
  108. fail "Unsupported arch: $ARCH"
  109. fi
  110. fi
  111. elif [[ "$OS" == osx ]]; then
  112. format="$(file -b "$1" | grep -o "[^ ]*$")"
  113. echo Format=$format
  114. if [[ "$ARCH" == x86_32 ]]; then
  115. assertEq $format "i386" $LINENO
  116. elif [[ "$ARCH" == x86_64 ]]; then
  117. assertEq $format "x86_64" $LINENO
  118. else
  119. fail "Unsupported arch: $ARCH"
  120. fi
  121. else
  122. fail "Unsupported system: $OS"
  123. fi
  124. echo
  125. }
  126. # Checks the dependencies of the artifact. Artifacts should only depend on
  127. # system libraries.
  128. # Usage: checkDependencies <path-to-protoc>
  129. checkDependencies ()
  130. {
  131. if [[ "$OS" == windows ]]; then
  132. dump_cmd='objdump -x '"$1"' | fgrep "DLL Name"'
  133. white_list="KERNEL32\.dll\|msvcrt\.dll"
  134. elif [[ "$OS" == linux ]]; then
  135. host_machine="$(uname -m)";
  136. dump_cmd='ldd '"$1"
  137. if [[ "$ARCH" == x86_32 ]]; then
  138. white_list="linux-gate\.so\.1\|libpthread\.so\.0\|libm\.so\.6\|libc\.so\.6\|ld-linux\.so\.2"
  139. elif [[ "$ARCH" == x86_64 ]]; then
  140. white_list="linux-vdso\.so\.1\|libpthread\.so\.0\|libm\.so\.6\|libc\.so\.6\|ld-linux-x86-64\.so\.2"
  141. elif [[ "$ARCH" == s390_64 ]]; then
  142. if [[ $host_machine != s390x ]];then
  143. dump_cmd='objdump -p '"$1"' | grep NEEDED'
  144. fi
  145. white_list="linux-vdso64\.so\.1\|libpthread\.so\.0\|libm\.so\.6\|libc\.so\.6\|libz\.so\.1\|ld64\.so\.1"
  146. elif [[ "$ARCH" == ppcle_64 ]]; then
  147. if [[ $host_machine != ppc64le ]];then
  148. dump_cmd='objdump -p '"$1"' | grep NEEDED'
  149. fi
  150. white_list="linux-vdso64\.so\.1\|libpthread\.so\.0\|libm\.so\.6\|libc\.so\.6\|libz\.so\.1\|ld64\.so\.2"
  151. elif [[ "$ARCH" == aarch_64 ]]; then
  152. dump_cmd='objdump -p '"$1"' | grep NEEDED'
  153. white_list="libpthread\.so\.0\|libm\.so\.6\|libc\.so\.6\|ld-linux-aarch64\.so\.1"
  154. fi
  155. elif [[ "$OS" == osx ]]; then
  156. dump_cmd='otool -L '"$1"' | fgrep dylib'
  157. white_list="libz\.1\.dylib\|libstdc++\.6\.dylib\|libSystem\.B\.dylib"
  158. fi
  159. if [[ -z "$white_list" || -z "$dump_cmd" ]]; then
  160. fail "Unsupported platform $OS-$ARCH."
  161. fi
  162. echo "Checking for expected dependencies ..."
  163. eval $dump_cmd | grep -i "$white_list" || fail "doesn't show any expected dependencies"
  164. echo "Checking for unexpected dependencies ..."
  165. eval $dump_cmd | grep -i -v "$white_list"
  166. ret=$?
  167. if [[ $ret == 0 ]]; then
  168. fail "found unexpected dependencies (listed above)."
  169. elif [[ $ret != 1 ]]; then
  170. fail "Error when checking dependencies."
  171. fi # grep returns 1 when "not found", which is what we expect
  172. echo "Dependencies look good."
  173. echo
  174. }
  175. ############################################################################
  176. echo "Building protoc, OS=$OS ARCH=$ARCH TARGET=$MAKE_TARGET"
  177. CONFIGURE_ARGS="--disable-shared"
  178. if [[ "$OS" == windows ]]; then
  179. MAKE_TARGET="${MAKE_TARGET}.exe"
  180. fi
  181. # Override the default value set in configure.ac that has '-g' which produces
  182. # huge binary.
  183. CXXFLAGS="-DNDEBUG"
  184. LDFLAGS=""
  185. if [[ "$(uname)" == CYGWIN* ]]; then
  186. assertEq "$OS" windows $LINENO
  187. # Use mingw32 compilers because executables produced by Cygwin compiler
  188. # always have dependency on Cygwin DLL.
  189. if [[ "$ARCH" == x86_64 ]]; then
  190. CONFIGURE_ARGS="$CONFIGURE_ARGS --host=x86_64-w64-mingw32"
  191. elif [[ "$ARCH" == x86_32 ]]; then
  192. CONFIGURE_ARGS="$CONFIGURE_ARGS --host=i686-pc-mingw32"
  193. else
  194. fail "Unsupported arch by CYGWIN: $ARCH"
  195. fi
  196. elif [[ "$(uname)" == MINGW32* ]]; then
  197. assertEq "$OS" windows $LINENO
  198. assertEq "$ARCH" x86_32 $LINENO
  199. elif [[ "$(uname)" == MINGW64* ]]; then
  200. assertEq "$OS" windows $LINENO
  201. assertEq "$ARCH" x86_64 $LINENO
  202. elif [[ "$(uname)" == Linux* ]]; then
  203. if [[ "$OS" == linux ]]; then
  204. if [[ "$ARCH" == x86_64 ]]; then
  205. CXXFLAGS="$CXXFLAGS -m64"
  206. elif [[ "$ARCH" == x86_32 ]]; then
  207. CXXFLAGS="$CXXFLAGS -m32"
  208. elif [[ "$ARCH" == aarch_64 ]]; then
  209. CONFIGURE_ARGS="$CONFIGURE_ARGS --host=aarch64-linux-gnu"
  210. elif [[ "$ARCH" == ppcle_64 ]]; then
  211. CXXFLAGS="$CXXFLAGS -m64"
  212. CONFIGURE_ARGS="$CONFIGURE_ARGS --host=powerpc64le-linux-gnu"
  213. elif [[ "$ARCH" == s390_64 ]]; then
  214. CXXFLAGS="$CXXFLAGS -m64"
  215. CONFIGURE_ARGS="$CONFIGURE_ARGS --host=s390x-linux-gnu"
  216. else
  217. fail "Unsupported arch: $ARCH"
  218. fi
  219. elif [[ "$OS" == windows ]]; then
  220. # Cross-compilation for Windows
  221. CONFIGURE_ARGS="$CONFIGURE_ARGS"
  222. if [[ "$ARCH" == x86_64 ]]; then
  223. CONFIGURE_ARGS="$CONFIGURE_ARGS --host=x86_64-w64-mingw32"
  224. elif [[ "$ARCH" == x86_32 ]]; then
  225. CONFIGURE_ARGS="$CONFIGURE_ARGS --host=i686-w64-mingw32"
  226. else
  227. fail "Unsupported arch: $ARCH"
  228. fi
  229. else
  230. fail "Cannot build $OS on $(uname)"
  231. fi
  232. elif [[ "$(uname)" == Darwin* ]]; then
  233. assertEq "$OS" osx $LINENO
  234. # Make the binary compatible with OSX 10.7 and later
  235. CXXFLAGS="$CXXFLAGS -mmacosx-version-min=10.7"
  236. if [[ "$ARCH" == x86_64 ]]; then
  237. CXXFLAGS="$CXXFLAGS -m64"
  238. elif [[ "$ARCH" == x86_32 ]]; then
  239. CXXFLAGS="$CXXFLAGS -m32"
  240. else
  241. fail "Unsupported arch: $ARCH"
  242. fi
  243. else
  244. fail "Unsupported system: $(uname)"
  245. fi
  246. # Statically link libgcc and libstdc++.
  247. # -s to produce stripped binary.
  248. if [[ "$OS" == windows ]]; then
  249. # Also static link libpthread required by mingw64
  250. LDFLAGS="$LDFLAGS -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread -s"
  251. elif [[ "$OS" != osx ]]; then
  252. # And they don't work under Mac.
  253. LDFLAGS="$LDFLAGS -static-libgcc -static-libstdc++ -s"
  254. fi
  255. export CXXFLAGS LDFLAGS
  256. # Nested double quotes are unintuitive, but it works.
  257. cd "$(dirname "$0")"
  258. WORKING_DIR="$(pwd)"
  259. BUILD_DIR="build/$OS/$ARCH"
  260. TARGET_FILE="target/$OS/$ARCH/$MAKE_TARGET.exe"
  261. mkdir -p "$BUILD_DIR" && cd "$BUILD_DIR" &&
  262. ../../../../configure $CONFIGURE_ARGS &&
  263. cd src && make $MAKE_TARGET -j8 &&
  264. cd "$WORKING_DIR" && mkdir -p $(dirname $TARGET_FILE) &&
  265. cp $BUILD_DIR/src/$MAKE_TARGET $TARGET_FILE ||
  266. exit 1
  267. if [[ "$OS" == osx ]]; then
  268. # Since Mac linker doesn't accept "-s", we need to run strip
  269. strip $TARGET_FILE || exit 1
  270. fi
  271. checkArch $TARGET_FILE && checkDependencies $TARGET_FILE