| |
| #---------------------------------------------------------------------- |
| # Emit 'version.go'. This file contains a series of Go constants that |
| # capture the target configuration (arch, OS, etc), emitted directly |
| # to a file (as opposed to generation via script). Based on the |
| # libgo Makefile recipe. |
| # |
| # Unnamed parameters: |
| # |
| # * GOOS setting (target OS) |
| # * GOARCH setting (target architecture) |
| # * output file |
| # * cmake binary directory for libfo |
| # * root of src containing libgo script files |
| # |
| function(mkversion goos goarch outfile bindir srcroot scriptroot) |
| |
| file(REMOVE ${outfile}) |
| file(WRITE ${outfile} "package sys\n") |
| |
| # FIXME: typical LLVM usage allows for performing a build without |
| # CMAKE_INSTALL_PREFIX set, then doing an install from the build |
| # using a newly chosen CMAKE_INSTALL_PREFIX value. This mode is |
| # not currently supported -- the install prefix has to be set properly |
| # as part of the original build. |
| |
| # Compiler version |
| file(STRINGS "${srcroot}/../VERSION" rawver) |
| string(STRIP ${rawver} ver) |
| # Default GOROOT var initialization. |
| file(APPEND ${outfile} "func init() { DefaultGoroot = \"${CMAKE_INSTALL_PREFIX}\" }\n") |
| file(APPEND ${outfile} "const TheVersion = ") |
| emitversionstring(${outfile} ${srcroot}) |
| file(APPEND ${outfile} "\n") |
| |
| # FIXME: |
| # GccgoToolDir is set to the gccgo installation directory that contains |
| # (among other things) "go1", "cgo", "cc1", and other auxiliary |
| # executables. Where things like "cgo" will live hasn't been ironed |
| # out yet, so just pick a spot in the bin directory for now. See also |
| # 'DefaultGoRoot' above. |
| file(APPEND ${outfile} "const GccgoToolDir = \"${CMAKE_INSTALL_PREFIX}/tools\"\n") |
| |
| # FIXME: add a real switch base on configuration params here. |
| |
| if( ${goarch} STREQUAL "amd64") |
| set(archfamily "AMD64") |
| set(bigendian "false") |
| set(cachelinesize "64") |
| set(physpagesize "4096") |
| set(pcquantum "1") |
| set(int64align "8") |
| set(minframesize 0) |
| elseif( ${goarch} STREQUAL "arm64") |
| # Simply picking up one typical setting |
| # Align with current sets in gofrontend/libgo/goarch.sh |
| set(archfamily "ARM64") |
| set(bigendian "false") |
| set(cachelinesize "32") |
| set(physpagesize "65536") |
| set(pcquantum "4") |
| set(int64align "8") |
| set(minframesize 8) |
| else() |
| message(FATAL_ERROR "unsupported arch ${goarch}: currently only amd64/arm64 support") |
| endif() |
| |
| file(APPEND ${outfile} "const Goexperiment = ``\n") |
| file(APPEND ${outfile} "const GOARCH = \"${goarch}\"\n") |
| file(APPEND ${outfile} "const GOOS = \"${goos}\"\n") |
| file(APPEND ${outfile} "\n") |
| file(APPEND ${outfile} "type ArchFamilyType int\n\n") |
| file(APPEND ${outfile} "const (\n") |
| file(APPEND ${outfile} "\tUNKNOWN ArchFamilyType = iota\n") |
| |
| foreach (af ${allgoarchfamily}) |
| file(APPEND ${outfile} "\t${af}\n") |
| endforeach() |
| file(APPEND ${outfile} ")\n\n") |
| |
| foreach (arch ${allgoarch}) |
| set(val "0") |
| if( ${arch} STREQUAL ${goarch}) |
| set(val "1") |
| endif() |
| upperfirst(${arch} "uparch") |
| file(APPEND ${outfile} "const Goarch${uparch} = ${val}\n") |
| endforeach() |
| file(APPEND ${outfile} "\n") |
| |
| set(constants "ArchFamily:family" "BigEndian:bigendian" "CacheLineSize:cachelinesize" "PhysPageSize:defaultphyspagesize" "PCQuantum:pcquantum" "Int64Align:int64align" "MinFrameSize:minframesize") |
| |
| file(APPEND ${outfile} "const (\n") |
| foreach(item ${constants}) |
| |
| # Split item into Go constant name and |
| string(REGEX REPLACE ":" " " sitem ${item}) |
| separate_arguments(sitem) |
| list(GET sitem 0 constname) |
| list(GET sitem 1 scriptarg) |
| |
| # Invoke goarch.sh |
| execute_process(COMMAND ${shell} "${scriptroot}/goarch.sh" |
| ${goarch} ${scriptarg} |
| OUTPUT_VARIABLE result |
| ERROR_VARIABLE errmsg |
| RESULT_VARIABLE exitstatus) |
| if(${exitstatus} MATCHES 0) |
| file(APPEND ${outfile} "\t${constname} = ${result}") |
| else() |
| message(FATAL_ERROR "goarch.sh invocation failed: ${errmsg}") |
| endif() |
| |
| endforeach() |
| |
| file(APPEND ${outfile} ")\n\n") |
| |
| foreach (os ${allgoos}) |
| set(val "0") |
| if( ${os} STREQUAL ${goos}) |
| set(val "1") |
| endif() |
| upperfirst(${os} "upos") |
| file(APPEND ${outfile} "const Goos${upos} = ${val}\n") |
| endforeach() |
| |
| file(APPEND ${outfile} "\n") |
| file(APPEND ${outfile} "type Uintreg uintptr\n") |
| endfunction() |
| |
| #---------------------------------------------------------------------- |
| # Emit 'cpugen.go'. Similar to version.go, but with a smaller set of |
| # CPU-specific constants. Based on the libgo Makefile recipe. |
| # |
| # Unnamed parameters: |
| # |
| # * GOARCH setting (target architecture) |
| # * output file |
| # * root of src containing libgo script files |
| # |
| function(mkcpugen goarch outfile scriptroot) |
| |
| file(REMOVE ${outfile}) |
| file(WRITE ${outfile} "package cpu\n") |
| |
| # Invoke goarch.sh |
| execute_process(COMMAND ${shell} "${scriptroot}/goarch.sh" |
| ${goarch} "cachelinesize" |
| OUTPUT_VARIABLE result |
| ERROR_VARIABLE errmsg |
| RESULT_VARIABLE exitstatus) |
| if(${exitstatus} MATCHES 0) |
| file(APPEND ${outfile} "const CacheLinePadSize = ${result}\n") |
| else() |
| message(FATAL_ERROR "goarch.sh invocation failed: ${errmsg}") |
| endif() |
| # For now this is hard-wired off. If/when gollvm supports |
| # PPC64 ELF ABI v1 we'll need to configure it. |
| file(APPEND ${outfile} "const FunctionDescriptors = false\n") |
| file(APPEND ${outfile} "\n") |
| |
| endfunction() |
| |
| #---------------------------------------------------------------------- |
| # Emit 'gcpugen.go', another cpu-specific generated Go file. Based |
| # on the libgo Makefile recipe. |
| # |
| # Unnamed parameters: |
| # |
| # * GOARCH setting (target architecture) |
| # * output file |
| # * root of src containing libgo script files |
| # |
| function(mkgcpugen goarch outfile scriptroot) |
| |
| file(REMOVE ${outfile}) |
| file(WRITE ${outfile} "package cpu\n") |
| |
| # Invoke goarch.sh |
| execute_process(COMMAND ${shell} "${scriptroot}/goarch.sh" |
| ${goarch} "cachelinesize" |
| OUTPUT_VARIABLE result |
| ERROR_VARIABLE errmsg |
| RESULT_VARIABLE exitstatus) |
| if(${exitstatus} MATCHES 0) |
| file(APPEND ${outfile} "const cacheLineSize = ${result}\n") |
| else() |
| message(FATAL_ERROR "goarch.sh invocation failed: ${errmsg}") |
| endif() |
| file(APPEND ${outfile} "\n") |
| |
| endfunction() |
| |
| macro(upperfirst name result) |
| string(SUBSTRING ${name} 0 1 c1) |
| string(SUBSTRING ${name} 1 -1 crem) |
| string(TOUPPER ${c1} upc1) |
| set(${result} "${upc1}${crem}") |
| endmacro() |
| |
| #---------------------------------------------------------------------- |
| # Emit compiler version string to specified output file. This is extracted |
| # out into a separate function since it is needed in a couple of different |
| # places. |
| # |
| # Unnamed parameters: |
| # |
| # * output file to target |
| # * root of libgo source |
| |
| function(emitversionstring outfile srcroot) |
| file(STRINGS "${srcroot}/../VERSION" rawver) |
| string(STRIP ${rawver} ver) |
| file(APPEND ${outfile} "\"${ver} gollvm LLVM ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}${LLVM_VERSION_SUFFIX}\"") |
| endfunction() |
| |
| #---------------------------------------------------------------------- |
| # Emit 'gccgosizes.go', which includes size and alignment constants |
| # by architecture. |
| # |
| # Unnamed parameters: |
| # |
| # * GOARCH setting for target |
| # * output file to target |
| # * directory containing libgo scripts |
| # |
| function(mkgccgosizes goarch outfile scriptroot) |
| |
| file(REMOVE ${outfile}) |
| file(WRITE ${outfile} "package types\n\n") |
| file(APPEND ${outfile} "var gccgoArchSizes = map[string]*StdSizes{\n") |
| foreach(arch ${allgoarch}) |
| |
| execute_process(COMMAND ${shell} "${scriptroot}/goarch.sh" |
| ${arch} "ptrsize" |
| OUTPUT_VARIABLE presult |
| ERROR_VARIABLE errmsg |
| RESULT_VARIABLE exitstatus) |
| if(NOT ${exitstatus} MATCHES 0) |
| message(FATAL_ERROR "goarch.sh invocation failed: ${errmsg}") |
| endif() |
| |
| execute_process(COMMAND ${shell} "${scriptroot}/goarch.sh" |
| ${arch} "maxalign" |
| OUTPUT_VARIABLE aresult |
| ERROR_VARIABLE errmsg |
| RESULT_VARIABLE exitstatus) |
| if(NOT ${exitstatus} MATCHES 0) |
| message(FATAL_ERROR "goarch.sh invocation failed: ${errmsg}") |
| endif() |
| |
| string(STRIP ${presult} presult) |
| string(STRIP ${aresult} aresult) |
| |
| file(APPEND ${outfile} "\"${arch}\": {${presult}, ${aresult}},\n") |
| endforeach() |
| file(APPEND ${outfile} "}\n") |
| endfunction() |
| |
| #---------------------------------------------------------------------- |
| # Emit 'objabi.go', containing default settings for various GO* vars. |
| # |
| # Unnamed parameters: |
| # |
| # * output file to target |
| # * libgo cmake binary directory |
| # * libgo source code root directory |
| # |
| function(mkobjabi outfile binroot srcroot) |
| |
| file(REMOVE ${outfile}) |
| file(WRITE ${outfile} "package objabi\n\n") |
| file(APPEND ${outfile} "import \"runtime\"\n") |
| |
| file(APPEND ${outfile} "func defaultGOROOTValue() string { return \"${GOLLVM_INSTALL_DIR}\" }\n") |
| |
| file(APPEND ${outfile} "const defaultGO386 = `sse2`\n") |
| file(APPEND ${outfile} "const defaultGOARM = `5`\n") |
| file(APPEND ${outfile} "const defaultGOMIPS = `hardfloat`\n") |
| file(APPEND ${outfile} "const defaultGOMIPS64 = `hardfloat`\n") |
| file(APPEND ${outfile} "const defaultGOOS = runtime.GOOS\n") |
| file(APPEND ${outfile} "const defaultGOPPC64 = `power8`\n") |
| file(APPEND ${outfile} "const defaultGOARCH = runtime.GOARCH\n") |
| file(APPEND ${outfile} "const defaultGO_EXTLINK_ENABLED = ``\n") |
| file(APPEND ${outfile} "const defaultGO_LDSO = ``\n") |
| file(APPEND ${outfile} "const version = ") |
| emitversionstring(${outfile} ${srcroot}) |
| file(APPEND ${outfile} "\n") |
| file(APPEND ${outfile} "const stackGuardMultiplierDefault = 1\n") |
| file(APPEND ${outfile} "const goexperiment = ``\n") |
| endfunction() |
| |
| #---------------------------------------------------------------------- |
| # Emit 'zstdpkglist.go', containing a map with all of the std Go packages. |
| # |
| # Unnamed parameters: |
| # |
| # * package to use for generated Go code |
| # * output file to target |
| # * list of go std library packages (does not include libgotool packages) |
| # |
| function(mkzstdpkglist package outfile libpackages) |
| file(REMOVE ${outfile}) |
| file(WRITE ${outfile} "package ${package}\n\n") |
| file(APPEND ${outfile} "var stdpkg = map[string]bool{") |
| foreach(pack ${libpackages}) |
| string(REGEX MATCH "^.*golang\.org\/.*$" matched ${pack}) |
| if(NOT matched) |
| file(APPEND ${outfile} "\"${pack}\": true,\n") |
| endif() |
| endforeach() |
| file(APPEND ${outfile} "\"unsafe\": true,\n") |
| file(APPEND ${outfile} "\"runtime/cgo\": true,\n") |
| file(APPEND ${outfile} "}\n") |
| endfunction() |
| |
| #---------------------------------------------------------------------- |
| # Emit 'zdefaultcc.go', containing info on where to find C/C++ compilers. |
| # |
| # Unnamed parameters: |
| # |
| # * package to use for generated Go code |
| # * output file to target |
| # * C compiler path |
| # * C++ compiler path |
| # |
| # Named parameters: |
| # |
| # EXPORT Generated public functions (ex: DefaultCC not defaultCC). |
| # |
| function(mkzdefaultcc package outfile ccpath cxxpath) |
| CMAKE_PARSE_ARGUMENTS(ARG "EXPORT" "" "" ${ARGN}) |
| |
| # Construct default driver path |
| set(driverpath "${GOLLVM_INSTALL_DIR}/bin/llvm-goc") |
| |
| file(REMOVE ${outfile}) |
| file(WRITE ${outfile} "package ${package}\n\n") |
| |
| set(f1 "defaultGCCGO") |
| set(f2 "defaultCC") |
| set(f3 "defaultCXX") |
| set(f4 "defaultPkgConfig") |
| set(v1 "oSArchSupportsCgo") |
| if( ${ARG_EXPORT} ) |
| upperfirst(${f1} "f1") |
| upperfirst(${f2} "f2") |
| upperfirst(${f3} "f3") |
| upperfirst(${f4} "f4") |
| upperfirst(${v1} "v1") |
| endif() |
| |
| file(APPEND ${outfile} "func ${f1}(goos, goarch string) string { return \"${driverpath}\" }\n") |
| file(APPEND ${outfile} "func ${f2}(goos, goarch string) string { return \"${ccpath}\" }\n") |
| file(APPEND ${outfile} "func ${f3}(goos, goarch string) string { return \"${cxxpath}\" }\n") |
| file(APPEND ${outfile} "const ${f4} = \"pkg-config\"\n") |
| file(APPEND ${outfile} "var ${v1} = map[string]bool{}\n") |
| endfunction() |
| |
| #---------------------------------------------------------------------- |
| # Emit 'epoll.go', containing info on the epoll syscall. Reads |
| # variables SIZEOF_STRUCT_EPOLL_EVENT and STRUCT_EPOLL_EVENT_FD_OFFSET |
| # previously set by config process. |
| # |
| # Unnamed parameters: |
| # |
| # * output file to target |
| # |
| function(mkepoll outfile) |
| file(REMOVE ${outfile}) |
| file(WRITE ${outfile} "package syscall\n\n") |
| |
| set(s ${SIZEOF_STRUCT_EPOLL_EVENT}) |
| set(o ${STRUCT_EPOLL_EVENT_FD_OFFSET}) |
| |
| file(APPEND ${outfile} "type EpollEvent struct {") |
| file(APPEND ${outfile} " Events uint32\n") |
| if(${s} EQUAL 0 AND ${o} EQUAL 0) |
| message(SEND_ERROR "*** struct epoll_event data.fd offset unknown") |
| elseif(${s} EQUAL 8 AND ${o} EQUAL 4) |
| file(APPEND ${outfile} " Fd int32\n") |
| elseif(${s} EQUAL 12 AND ${o} EQUAL 4) |
| file(APPEND ${outfile} " Fd int32\n Pad [4]byte\n") |
| elseif(${s} EQUAL 12 AND ${o} EQUAL 8) |
| file(APPEND ${outfile} " Pad [4]byte\n Fd int32\n") |
| elseif(${s} EQUAL 16 AND ${o} EQUAL 8) |
| file(APPEND ${outfile} " Pad [4]byte\n Fd int32\n Pad2 [4]byte\n ") |
| else() |
| message(SEND_ERROR "*** struct epoll_event data.fd offset unknown") |
| endif() |
| file(APPEND ${outfile} "}\n") |
| endfunction() |
| |
| #---------------------------------------------------------------------- |
| # Emit 'syscall_arch.go', containing arch and os constants. |
| # |
| # Unnamed parameters: |
| # |
| # * output file to target |
| # * GOOS setting (target OS) |
| # * GOARCH setting (target architecture) |
| # |
| function(mksyscallarch outfile goos goarch) |
| file(REMOVE ${outfile}) |
| file(WRITE ${outfile} "package syscall\n\n") |
| file(APPEND ${outfile} "const ARCH = \"${goarch}\"\n") |
| file(APPEND ${outfile} "const OS = \"${goos}\"\n") |
| endfunction() |
| |
| # This helper function provides a general mechanism for running a |
| # shell script to emit a Go code to a temp file, then adds a cmake |
| # target that copies the temp to a specific *.go file if the temp |
| # is different. |
| # |
| # Example usage: |
| # |
| # generate_go_from_script(outfile script goos goarch workdir DEP <deps>) |
| # |
| # Unnamed parameters: |
| # |
| # * generated Go source file (this should be a full path) |
| # * script to run |
| # * GOOS setting (target OS) |
| # * GOARCH setting (target architecture) |
| # * working bin directory |
| # |
| # Named parameters: |
| # |
| # CAPTURE Capture stdout from script into output file. |
| # SCRIPTARGS Additional args to pass to script. |
| # DEP Things that the generated file should depend on. |
| # |
| |
| function(generate_go_from_script outpath script goos goarch workdir) |
| CMAKE_PARSE_ARGUMENTS(ARG "CAPTURE" "" "DEP;SCRIPTARGS" ${ARGN}) |
| |
| get_filename_component(outfile "${outpath}" NAME) |
| get_filename_component(outdir "${outpath}" DIRECTORY) |
| set(tmpfile "${outdir}/tmp-${outfile}") |
| if(DEFINED ENV{SHELL}) |
| set(shell $ENV{SHELL}) |
| else() |
| set(shell "/bin/bash") |
| endif() |
| |
| # Create a rule that runs the script into a temporary file. |
| if( NOT ARG_CAPTURE ) |
| add_custom_command( |
| # For this variant, the assumption is that the script writes it |
| # output to a specified file. |
| OUTPUT ${tmpfile} |
| COMMAND "GOARCH=${goarch}" "GOOS=${goos}" |
| "${shell}" ${script} ${ARG_SCRIPTARGS} |
| COMMENT "Creating ${tmpfile}" |
| DEPENDS ${script} ${ARG_DEP} |
| WORKING_DIRECTORY ${workdir} |
| VERBATIM) |
| else() |
| # For this variant, the script is emitting output to stdout, |
| # which we need to capture and redirect to a file. |
| set(capturesh "${CMAKE_CURRENT_SOURCE_DIR}/capturescript.sh") |
| add_custom_command( |
| OUTPUT ${tmpfile} |
| COMMAND "GOARCH=${goarch}" "GOOS=${goos}" |
| "${shell}" ${capturesh} ${script} ${tmpfile} ${ARG_SCRIPTARGS} |
| COMMENT "Creating ${tmpfile}" |
| DEPENDS ${script} ${ARG_DEP} |
| WORKING_DIRECTORY ${workdir} |
| VERBATIM) |
| endif() |
| |
| # Create a rule that copies tmp file to output file if different. |
| copy_if_different(${tmpfile} ${outpath}) |
| endfunction() |
| |
| # This function manages the cmake rules for the auto-generated |
| # 'gen-sysinfo.go' file, which contains type information derived from |
| # compiling a C program that includes various system headers. |
| # |
| # Unnamed parameters: |
| # |
| # * name of tmpfile into which to generate provisional Go code |
| # * name of generated Go source file for final Go code |
| # * name of macro temp file to generate |
| # * name of temp object file to write |
| # * path to godumpspec tool |
| # * path to sysinfo.c |
| # |
| # Names params: |
| # |
| # * DEPS -- things gen-sysinfo.go is dependent on (ex: config.h) |
| # * CFLAGS -- additional compile options (ex: -I ...) |
| # |
| function(mkgensysinfo tmpfile outfile macrofile objfile godumpspec sysinfoc) |
| CMAKE_PARSE_ARGUMENTS(ARG "" "" "DEPS;CFLAGS" ${ARGN}) |
| |
| set(ccomp ${CMAKE_C_COMPILER}) |
| set(cflags ${ARG_CFLAGS}) |
| if(NOT "${CMAKE_SYSROOT}" STREQUAL "") |
| set(cflags ${cflags} "--sysroot=${CMAKE_SYSROOT}") |
| endif() |
| |
| # Run the host C compiler to generate the object. NB: clang will |
| # accept -fno-eliminate-unused-debug-types but does not actually |
| # implement this functionality. |
| add_custom_command( |
| OUTPUT ${objfile} |
| COMMAND ${ccomp} "-g3" "-c" "-fno-eliminate-unused-debug-types" |
| ${sysinfoc} -o ${objfile} ${cflags} |
| DEPENDS ${sysinfoc} ${ARG_DEPS} |
| COMMENT "Building sysinfo.o " |
| VERBATIM) |
| |
| # Another compile to build the macro temp file. |
| add_custom_command( |
| OUTPUT ${macrofile} |
| COMMAND ${ccomp} "-E" "-dM" |
| ${sysinfoc} -o ${macrofile} ${cflags} |
| DEPENDS ${sysinfoc} ${ARG_DEPS} |
| COMMENT "Building sysinfo.c macro temp file" |
| VERBATIM) |
| |
| # Next step is to run the llvm-godumpspec utility, which consumes |
| # the two files produced above and generates the Go file in question. |
| add_custom_command( |
| OUTPUT ${tmpfile} |
| COMMAND ${godumpspec} |
| "--macrotmp=${macrofile}" "--object=${objfile}" "--output=${tmpfile}" |
| DEPENDS ${objfile} ${macrofile} ${ARG_DEPS} |
| COMMENT "Generating ${outfile}" |
| VERBATIM) |
| |
| # Create a rule that copies tmpfile to output file if different. |
| copy_if_different(${tmpfile} ${outfile}) |
| |
| endfunction() |