1#!/bin/sh 2############################################################################# 3## 4## This file is part of GAP, a system for computational discrete algebra. 5## 6## Copyright of GAP belongs to its developers, whose names are too numerous 7## to list here. Please refer to the COPYRIGHT file for details. 8## 9## SPDX-License-Identifier: GPL-2.0-or-later 10## 11## 12#W gac, the GAP compiler 13## 14## gac [-d] [-c|-C] [-o <output>] {-f<option>} <input>... 15## 16## 'gac' compiles the input files. Input files must be GAP source code 17## (suffix '.g' or '.gap'), C source code (suffix '.c'), or compiled code 18## files (suffix '.o'). 19## 20## If '-d' is given then the code is compiled for dynamic loading 21## 22## If neither '-c' nor '-C' is given, then 'gac' compiles the code completely, 23## producing a new kernel for static compilation or a dynamically loadable '.so' 24## file for dynamic compilation. 25## 26## If '-c' is given, then 'gac' only compiles the input files to 27## '.o' object files, which must be further linked to make a static kernel or 28## dynamically loadable module 29## 30## If '-C is given, then 'gac' only compiles the input files to C code, which 31## will require compilation and linking to be usable. 32## 33## If '-r' is given, then statically compiled files will be assumed to be given 34## by pathnames relative to the GAP root, and will be compiled for automatic loading 35## when files are sought relative to the GAP root. 36## 37## The option '-o <output>' tells 'gac' to name the output file <output>. 38## 39## The option '-save-temps' tells 'gac' to not delete any intermediate files 40## 41## The option '-p <option>' tells 'gac' to pass the option <option> to the 42## C compiler. 43## 44## The option '-P <option>' tells 'gac' to pass the option <option> to the 45## C linker. 46## 47## The option '-L <option>' tells 'gac' to pass the option <option> 48## to the C linker when linking dynamic modules. Contrary to -P the 49## option is appended at the end of the link command after the .o 50## files to link. 51## 52## other options: 53## -k|--gap-compiler 54## 55 56SHELL="@SHELL@" 57 58# absolute path of the directory in which GAP was compiled 59abs_top_builddir="@abs_top_builddir@" 60 61# path of the directory the GAP sources contained in 62abs_top_srcdir="@abs_top_srcdir@" 63 64# 65libdir="@libdir@" 66 67# path to the GAP executable 68gap_compiler="${abs_top_builddir}/gap" 69 70libtool="$SHELL $abs_top_builddir/libtool" 71CC="@CC@" 72 73# These three should be filled in by the standard autoconf procedures 74c_compiler="$libtool --mode=compile $CC" 75c_linker="$libtool --mode=link $CC" 76 77# read sysinfo.gap, which should set GAP_CFLAGS, GAP_CPPFLAGS, GAP_LDFLAGS, GAP_LIBS 78. "${abs_top_builddir}/sysinfo.gap" 79 80# These will need special care 81c_dyn_linker="$libtool --mode=link $CC -module -avoid-version -rpath $libdir" 82c_addlibs="" 83 84GAPARCH=@GAPARCH@ 85SYS_IS_CYGWIN32=@SYS_IS_CYGWIN32@ 86if [ X"$SYS_IS_CYGWIN32" = X"yes" ] ; then 87 c_dyn_linker="$c_dyn_linker -no-undefined -version-info 0:0:0" 88 # FIXME: use correct DLL path (also after "make install") 89 c_dyn_linker="$c_dyn_linker -Wl,${abs_top_builddir}/bin/${GAPARCH}/gap.dll" 90fi 91 92 93############################################################################# 94## 95#F gap_compile <output> <input> <module-name> <identifier> 96## 97gap_compile () { 98 echo ${gap_compiler} -C $1 $2 $3 $4 99 ${gap_compiler} -C "$1" "$2" "$3" "$4" 100} 101 102 103############################################################################# 104## 105#F c_compile <output> <input> <options> 106## 107c_compile () { 108 echo ${c_compiler} $3 -o $1 ${GAP_CPPFLAGS} -c $2 109 ${c_compiler} $3 -o $1 ${GAP_CPPFLAGS} -c $2 || exit 1 110} 111 112 113############################################################################# 114## 115#F c_link_dyn <output> <input> 116## 117c_link_dyn () { 118 echo ${c_dyn_linker} ${GAP_LDFLAGS} -o $1 $2 ${c_addlibs} 119 output_la=${1%.so}.la 120 output_dir=$(dirname $1) 121 ${c_dyn_linker} ${GAP_LDFLAGS} -o "$output_la" $2 ${c_addlibs} || exit 1 122 if [ X"$SYS_IS_CYGWIN32" = X"yes" ] ; then 123 # GAP assumes shared libraries end in .so 124 for dllfile in `cd $output_dir/.libs; ls *.dll`; do 125 cp $output_dir/.libs/$dllfile $output_dir/${dllfile%.dll}.so 126 done 127 else 128 cp $output_dir/.libs/*.so $output_dir 129 fi; 130} 131 132 133############################################################################# 134## 135#F c_link <output> <inputs_o> 136## 137c_link () { 138 echo ${c_linker} ${GAP_LDFLAGS} -o $1 $2 ${GAP_LIBS} 139 ${c_linker} ${GAP_LDFLAGS} -o $1 $2 ${GAP_LIBS} || exit 1 140} 141 142############################################################################# 143## 144#F process_o_file <basename> <filename> 145## 146## Compile according to comp_mode and comp_howfar 147## 148## This does everything except the final link phase in the static case 149## in that case it adds the basename and object file path of $names and $objects 150## 151 152process_o_file () { 153 name=$1 154 o_file=$2 155 156 # the GAP compiler replaces _ by __ in names, so adjust here, too 157 name="$(echo "$name" | sed 's/_/__/g')" 158 159 # just remember for the linking stage later 160 names="${names} ${name}" 161 objects="${objects} $o_file" 162} 163 164############################################################################# 165## 166#F process_c_file <basename> <filename> 167## 168## Compile according to comp_mode and comp_howfar 169## 170## This does everything except the final link phase in the static case 171## in that case it adds the basename and object file path of $names and $objects 172## 173 174process_c_file () { 175 name=$1 176 c_file=$2 177 extra_cflags=$3 178 179 if [ $comp_howfar != "object" ]; then 180 o_file=${gactmp}/$$_${name}.lo 181 temps_o="${temps_o} ${o_file}" 182 elif [ "X$output" != "X" ]; then 183 o_file=$output 184 else 185 o_file=${name}.lo 186 fi 187 c_compile $o_file $c_file "$GAP_CFLAGS $extra_cflags" 188 if [ $comp_howfar = "link" ]; then 189 process_o_file $name $o_file 190 fi 191} 192 193############################################################################# 194## 195#F process_gap_file <filename> <ext> 196## 197## Compile according to comp_mode and comp_howfar 198## 199## This does everything except the final link phase in the static case 200## in that case it adds the basename and object file path of $names and $objects 201## 202 203process_gap_file () { 204 name=$(basename $1 $2) 205 206 if [ $comp_howfar != "c_code" ]; then 207 c_file=${gactmp}/$$_${name}.c 208 temps_c="${temps_c} $c_file" 209 elif [ "X$output" = "X" ]; then 210 c_file=${name}.c 211 else 212 c_file=$output 213 fi 214 gap_compile_in=$input 215 gap_compile_name=$input 216 if [ $comp_mode = "comp_static" ]; then 217 gap_compile_id=Init_${name} 218 if [ $comp_static_root_relative = "yes" ]; then 219 gap_compile_in=${abs_top_srcdir}/$input; 220 gap_compile_name=GAPROOT/$input; 221 fi 222 else 223 gap_compile_id=Init_Dynamic 224 fi 225 gap_compile $c_file ${gap_compile_in} $gap_compile_id ${gap_compile_name} 226 if [ $comp_howfar != "c_code" ]; then 227 process_c_file $name $c_file 228 if [ "$savetemps" = "true" ]; then 229 echo "Leaving C file " $c_file 230 else 231 echo rm -f $c_file 232 rm -f $c_file 233 fi 234 fi 235} 236 237############################################################################# 238## 239#F clean_up 240## 241clean_up () { 242 if [ "$savetemps" = "true" ]; then 243 echo "Leaving files on cleanup: " ${temps_c} ${temps_o} 244 else 245 echo rm -f ${temps_c} ${temps_o} 246 rm -f ${temps_c} ${temps_o} 247 fi 248} 249trap "clean_up" 2 3 250 251 252############################################################################# 253## 254## parse the arguments 255## 256if [ $# = 0 ]; then 257 echo "usage: $0 [-d|-r] [-c|-C] [-o <output>] <input>..." 258 exit 1 259fi 260 261comp_mode="comp_static" 262comp_howfar="link" 263comp_static_root_relative="no" 264output="" 265inputs="" 266savetemps="false" 267 268while [ $# -gt 0 ]; do 269 case $1 in 270 271 -c|--compile) comp_howfar="object";; 272 273 -d|--dynamic) comp_mode="comp_dyna";; 274 275 -C|--create-c) comp_howfar="c_code";; 276 277 -o|--output) shift; output="$1";; 278 279 -r) comp_static_root_relative="yes";; 280 281 -save-temps) savetemps="true";; 282 283 -f*) echo "$0: no such option '$1'" 284 exit 1;; 285 286 -k|--gap-compiler) shift; gap_compiler="$1";; 287 288 -p) shift; GAP_CFLAGS="${GAP_CFLAGS} $1";; 289 290 -P) shift; GAP_LDFLAGS="${GAP_LDFLAGS} $1";; 291 292 -L|--addlibs) shift; c_addlibs="${c_addlibs} $1";; 293 294 *.g|*.gap|*.gd|*.gi|*.c|*.cc|*.cpp|*.cxx|*.s|*.o|*.lo) 295 inputs="${inputs} $1";; 296 297 *) echo "$0: cannot handle this argument '$1'" 298 exit 1;; 299 300 esac 301 shift 302done 303 304if [ "X${inputs}" = "X" ]; then 305 echo "$0: no input files given" 306 exit 1 307fi 308 309 310 311 312############################################################################# 313## 314#F make_compstat 315## 316 317make_compstat () { 318 # make 'compstat.c' and compile it 319 temps_c="${temps_c} ${gactmp}/$$compstat.c" 320 ( 321 echo "/* made by 'gac', can be thrown away */" 322 echo "#include \"compiled.h\"" 323 324 echo "#ifndef AVOID_PRECOMPILED" 325 echo "extern StructInitInfo * Init__type1 ( void );" 326 echo "extern StructInitInfo * Init__oper1( void );" 327 echo "#endif" 328 329 for name in ${names}; do 330 echo "extern StructInitInfo * Init__${name} ( void );" 331 done 332 333 echo "InitInfoFunc CompInitFuncs [] = {" 334 echo "#ifndef AVOID_PRECOMPILED" 335 echo " Init__type1," 336 echo " Init__oper1," 337 echo "#endif" 338 339 for name in ${names}; do 340 echo " Init__${name}," 341 done 342 echo " 0" 343 echo "};" 344 ) > ${gactmp}/$$compstat.c 345 346 temps_o="${gactmp}/$$compstat.lo ${temps_o}" 347 c_compile ${gactmp}/$$compstat.o ${gactmp}/$$compstat.c "${GAP_CFLAGS}" 348 if [ "$savetemps" = "true" ]; then 349 echo "Leaving temp file " ${gactmp}/$$compstat.c 350 else 351 echo rm -f ${gactmp}/$$compstat.c 352 rm -f ${gactmp}/$$compstat.c 353 fi 354 objects="${gactmp}/$$compstat.lo ${objects}" 355} 356 357make_tmpdir () { 358 if command -v mktemp >/dev/null 2>&1 ; then 359 gactmp=$(mktemp -d -t "gacXXXXXXX") 360 else 361 basetmp=${TMPDIR:-/tmp}; #honor the TMPDIR environment variable. 362 gactmp="$basetmp/gac$$"; 363 mkdir "$gactmp" || exit 1; 364 fi 365} 366 367############################################################################# 368## 369## main loop 370## 371 372#Make temporary directory 373make_tmpdir; 374 375# loop over the input files 376for input in ${inputs}; do 377 case $input in 378 379 *.g) process_gap_file $input .g;; 380 *.gap) process_gap_file $input .gap;; 381 *.gd) process_gap_file $input .gd;; 382 *.gi) process_gap_file $input .gi;; 383 384 *.c) # compile '.c' source files 385 name=$(basename ${input} .c) 386 process_c_file $name $input;; 387 388 *.cc) # compile '.cc' source files (C++) 389 name=$(basename ${input} .cc) 390 process_c_file $name $input "-x c++";; 391 392 *.cpp) # compile '.cpp' source files (also C++) 393 name=$(basename ${input} .cpp) 394 process_c_file $name $input "-x c++";; 395 396 *.s) # compile '.s' source files (assembler) 397 name=$(basename ${input} .s) 398 process_c_file $name $input;; # HACK: just use the C compiler 399 400 *.o) # look over '.o' source files 401 name=$(basename ${input} .o) 402 process_o_file $name $input;; 403 404 *.lo) # look over '.lo' source files 405 name=$(basename ${input} .lo) 406 process_o_file $name $input;; 407 esac 408 done 409 410 411# static link phase 412if [ $comp_howfar = "link" ]; then 413 if [ $comp_mode = "comp_static" ]; then 414 make_compstat 415 416 # link everything together 417 if [ "X${output}" = "X" ]; then output="gacout"; fi 418 419 for object in $GAP_OBJS; do 420 if [ ${object} != "obj/src/compstat.lo" ]; then 421 objects="${abs_top_builddir}/${object} ${objects}" 422 fi 423 done 424 425 c_link ${output} "${objects}" 426 427 else 428 if [ "X${output}" = "X" ]; then output="${name}.la"; fi 429 c_link_dyn ${output} "${objects}" 430 fi 431 432 if [ "$savetemps" = "true" ]; then 433 echo "Leaving object files " ${temps_o} 434 else 435 echo rm -f ${temps_o} 436 rm -f ${temps_o} 437 fi 438fi 439 440# Remove temporary directory. 441# We may assume it is empty at this stage. 442if [ "$savetemps" = "false" ]; then 443 rm -rf "${gactmp}/.libs" 444 rmdir "${gactmp}" 445fi 446