amberc.sh 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. #!/bin/bash
  2. #
  3. # This is a "compiler" for Amber code. Run without arguments for help.
  4. #
  5. # Get Amber root directory from the location of this script so that
  6. # we can find the st and js directories etc.
  7. # Earlier we used this but it does not work on Mac
  8. # Amber=$(readlink -f `dirname ${0}`/..)
  9. TARGET=`dirname ${0}`/..
  10. pushd . >/dev/null
  11. cd $TARGET
  12. AMBER="`\pwd -P`"
  13. popd >/dev/null
  14. function usage {
  15. cat <<ENDOFHELP
  16. Usage: $0 [-l lib1,lib2...] [-i file] [-m class] [-M file]
  17. [-o] [-O|-A] [-d] [-s suffix] [-S suffix] [file1 [file2 ...]] [Program]
  18. Will compile Amber files - either separately or into a runnable complete
  19. program. If no .st files are listed only a linking stage is performed.
  20. Files listed will be handled using these rules:
  21. *.js
  22. Files are linked (concatenated) in listed order.
  23. If not found we look in $AMBER/js
  24. *.st
  25. Files are compiled into .js files before concatenated.
  26. If not found we look in $AMBER/st.
  27. NOTE: Each file is currently considered to be a fileout of a single class
  28. category of the same name as the file!
  29. If no Program is specified each given .st file will be compiled into
  30. a .js file. Otherwise a <Program>.js file is linked together based on
  31. the options:
  32. -l library1,library2
  33. Additionally add listed libraries (no spaces or .js) in listed order.
  34. -i file
  35. Add library initializer <file> instead of default $AMBER/js/init.js
  36. -m class
  37. Add at end a call to #main in class <class>.
  38. -M file
  39. Add at end javascript file <file> acting as main.
  40. -o
  41. Optimize each js file using the Google closure compiler.
  42. Using Closure compiler found at ~/compiler.jar
  43. -O
  44. Optimize final <Program>.js using the Google closure compiler.
  45. Using Closure compiler found at ~/compiler.jar
  46. -A Same as -O but use --compilation_level ADVANCED_OPTIMIZATIONS
  47. -d
  48. Additionally export code for deploy - stripped from source etc.
  49. Uses suffix ".deploy.js" in addition to any explicit given suffic using -s.
  50. -s suffix
  51. Add <suffix> to compiled js files so that File.st is compiled into
  52. File.<suffix>.js.
  53. -S suffix
  54. Use <suffix> for all libraries accessed using -L or -l. This makes it possible
  55. to have multiple flavors of Amber and libraries in the same place.
  56. Example invocations:
  57. Just compile Kernel-Objects.st to Kernel-Objects.js:
  58. amberc Kernel-Objects.st
  59. Compile Hello.st to Hello.js and create complete program called
  60. Program.js and adding a call to class method #main in class Hello:
  61. amberc -m Hello Hello.st Program
  62. Compile two .st files into corresponding .js files,
  63. and link with specific myboot.js, myKernel.js, myinit.js
  64. and main.js and create complete program called Program.js:
  65. amberc -M main.js myinit.js myboot.js myKernel.js Cat1.st Cat2.st Program
  66. ENDOFHELP
  67. exit 1;
  68. }
  69. # Check we at least got one argument
  70. if [ -z $1 ] ; then
  71. usage
  72. fi
  73. # Define our predefined library combinations
  74. KERNEL="boot Kernel-Objects Kernel-Classes Kernel-Methods Kernel-Collections Kernel-Exceptions Kernel-Transcript Kernel-Announcements"
  75. COMPILER="$KERNEL parser Compiler Compiler-Exceptions"
  76. # Predefined initializer
  77. INITIALIZER="$AMBER/js/init.js"
  78. # Default values
  79. ENV=
  80. INIT=$INITIALIZER
  81. MAIN=
  82. MAINFILE=
  83. BASE=$KERNEL
  84. LOAD=
  85. CLOSUREOPTS=
  86. # Ok, bad coding practice but hey, who would use such a suffix?
  87. SUFFIX=no-silly-suffix
  88. SUFFIXUSED=
  89. DEPLOY=false
  90. NODECOMPILE=nodecompile
  91. # Read options and shift them away
  92. while getopts "l:i:m:M:oOAds:S:h?" o; do
  93. case "$o" in
  94. l) LOAD=$OPTARG;;
  95. i) INIT=$OPTARG;;
  96. m) MAIN=$OPTARG;;
  97. M) MAINFILE=$OPTARG;;
  98. o) CLOSURE=true
  99. CLOSUREPARTS=true;;
  100. O) CLOSURE=true
  101. CLOSUREFULL=true;;
  102. A) CLOSURE=true
  103. CLOSUREOPTS="$CLOSUREOPTS --compilation_level ADVANCED_OPTIMIZATIONS"
  104. CLOSUREFULL=true;;
  105. d) DEPLOY=true;;
  106. s) SUFFIX=$OPTARG
  107. SUFFIXUSED=$SUFFIX;;
  108. S) LOADSUFFIX=$OPTARG
  109. SUFFIXUSED=$SUFFIX;;
  110. h) usage;;
  111. [?]) usage;;
  112. esac
  113. done
  114. shift $(($OPTIND - 1))
  115. # Check for Closure compiler and Java
  116. if [ ! -z $CLOSURE ]; then
  117. java > /dev/null
  118. if [ $? -eq 0 ]; then
  119. if [ ! -f ~/compiler.jar ]; then
  120. echo "Can not find Closure compiler at ~/compiler.jar"
  121. exit 1
  122. fi
  123. else
  124. echo "java is not installed and is needed for -O, -A or -o (Closure compiler)."
  125. exit 1
  126. fi
  127. fi
  128. # Function for looking up listed js files
  129. function resolvejs {
  130. FNAME="$1$LOADSUFFIX.js"
  131. if [ -f $FNAME ]; then
  132. RESOLVED="$FNAME"
  133. else
  134. if [ -f $AMBER/js/$FNAME ]; then
  135. RESOLVED="$AMBER/js/$FNAME"
  136. else
  137. echo "Javascript file not found: $FNAME"
  138. exit 1
  139. fi
  140. fi
  141. }
  142. # Resolve listed libraries in $BASE deparated by spaces
  143. for FILE in $BASE
  144. do
  145. resolvejs $FILE
  146. TOBASE="$TOBASE $RESOLVED"
  147. done
  148. # Resolve listed libraries in $LOAD separated by ,
  149. LOAD=${LOAD//,/\ }
  150. for FILE in $LOAD
  151. do
  152. resolvejs $FILE
  153. TOLOAD="$TOLOAD $RESOLVED"
  154. done
  155. # Resolve COMPILER
  156. for FILE in $COMPILER
  157. do
  158. resolvejs $FILE
  159. TOCOMPILER="$TOCOMPILER $RESOLVED"
  160. done
  161. # Add supplied libraries we have not already loaded (they are already resolved)
  162. #for FILE in $EXTRA
  163. #do
  164. # resolvejs $FILE
  165. # TOEXTRA="$TOEXTRA $RESOLVED"
  166. #done
  167. TOCOMPILER="$TOCOMPILER$TOLOAD"
  168. # Resolve init and nodecompile
  169. THEREST="init $AMBER/bin/$NODECOMPILE"
  170. for FILE in $THEREST
  171. do
  172. resolvejs $FILE
  173. TOCOMPILER="$TOCOMPILER $RESOLVED"
  174. done
  175. # Add supplied libraries
  176. LIBS="$TOBASE $TOLOAD"
  177. # Get a unique tempdir and make it get auto removed on exit
  178. TMPDIR=`mktemp -d amberc.XXXXXX 2>>/dev/null` ||\
  179. TMPDIR=/tmp/amberc.$$.`date +%s` && mkdir -p $TMPDIR
  180. trap "rm -rf $TMPDIR" EXIT
  181. # --------------------------------------------------
  182. # Collect libraries and Smalltalk files looking
  183. # both locally and in $AMBER/js and $AMBER/st
  184. # --------------------------------------------------
  185. PROGRAM=
  186. until [ "$*" = "" ]
  187. do
  188. case $1 in
  189. *.st)
  190. CATEGORY=`basename $1 .st`
  191. if [ -f "$1" ]; then
  192. COMPILE="$COMPILE $1 $CATEGORY"
  193. COMPILED="$COMPILED $CATEGORY$SUFFIXUSED.js"
  194. else
  195. if [ -f $AMBER/st/$1 ]; then
  196. COMPILE="$COMPILE $AMBER/st/$1 $CATEGORY"
  197. COMPILED="$COMPILED $CATEGORY$SUFFIXUSED.js"
  198. else
  199. echo "Amber file not found: $1"
  200. exit 1
  201. fi
  202. fi
  203. ;;
  204. *.js)
  205. resolvejs $1
  206. LIBS="$LIBS $RESOLVED"
  207. ;;
  208. *)
  209. # Will end up being the last non js/st argument
  210. PROGRAM=$1
  211. ;;
  212. esac
  213. shift
  214. done
  215. # --------------------------------------------------
  216. # Actual compilation phase of collected .st files
  217. # --------------------------------------------------
  218. # Create compiler dynamically
  219. cat $TOCOMPILER > $TMPDIR/compiler.js
  220. # Compile all collected .st files to .js
  221. echo "Loading libraries$TOCOMPILER and compiling ..."
  222. node $TMPDIR/compiler.js $DEPLOY $SUFFIX $COMPILE
  223. # Verify all .js files corresponding to .st files were created, otherwise exit
  224. IFS=" "
  225. for FILE in $COMPILED
  226. do
  227. if [ ! -f "$FILE" ]; then
  228. echo "Failed compilation of $FILE, exiting."
  229. exit 1
  230. fi
  231. done
  232. if [ ! -z $CLOSUREPARTS ]; then
  233. echo "Compiling all js files using Google closure compiler."
  234. ALLJSFILES="$COMPILED $LIBS"
  235. for FILE in $ALLJSFILES
  236. do
  237. mv $FILE $FILE.original
  238. java -jar ~/compiler.jar $CLOSUREOPTS --js $FILE.original --js_output_file $FILE
  239. rm $FILE.original
  240. done
  241. fi
  242. if [ -z $PROGRAM ]; then
  243. echo "Done."
  244. exit 0
  245. fi
  246. # --------------------------------------------------
  247. # Now we start composing resulting javascript file.
  248. # --------------------------------------------------
  249. # Add collected libraries to libs.js file.
  250. if [ ! -z "$LIBS" ]; then
  251. echo "Adding libraries $LIBS ..."
  252. cat $LIBS > $TMPDIR/libs.js
  253. LIBS=$TMPDIR/libs.js
  254. fi
  255. echo "Adding Amber code$COMPILED ..."
  256. # Check for init file
  257. if [ ! -z "$INIT" ]; then
  258. if [ -f "$INIT" ]; then
  259. echo "Adding initializer $INIT ..."
  260. else
  261. echo "Can not find init file $INIT, exiting."
  262. exit 1
  263. fi
  264. fi
  265. # Check for adding main
  266. if [ ! -z "$MAIN" ]; then
  267. echo "Adding call to $MAIN class >> main ..."
  268. echo "smalltalk.$MAIN._main()" > $TMPDIR/main.js
  269. MAIN=$TMPDIR/main.js
  270. fi
  271. # Check for adding main file
  272. if [ ! -z "$MAINFILE" ]; then
  273. if [ -f "$MAINFILE" ]; then
  274. echo "Adding main as $MAINFILE ..."
  275. else
  276. echo "Can not find main file $MAINFILE, exiting."
  277. exit 1
  278. fi
  279. MAIN=$MAINFILE
  280. fi
  281. # And finally concatenate Program.js
  282. echo "Writing $PROGRAM.js ..."
  283. cat $LIBS $COMPILED $INIT $MAIN > $PROGRAM.js
  284. echo "Done."
  285. if [ ! -z $CLOSUREFULL ]; then
  286. echo "Compiling $PROGRAM.js file using Google closure compiler."
  287. mv $PROGRAM.js $PROGRAM.js.original
  288. java -jar ~/compiler.jar $CLOSUREOPTS --js $PROGRAM.js.original --js_output_file $PROGRAM.js
  289. rm $PROGRAM.js.original
  290. echo "Done."
  291. fi