diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index deaa719c56..d073ca9538 100755 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -3078,7 +3078,12 @@ Nim: color: "#37775b" extensions: - ".nim" + - ".nim.cfg" + - ".nimble" - ".nimrod" + - ".nims" + filenames: + - nim.cfg ace_mode: text tm_scope: source.nim language_id: 249 diff --git a/samples/Nim/config.nims b/samples/Nim/config.nims new file mode 100644 index 0000000000..d39b007508 --- /dev/null +++ b/samples/Nim/config.nims @@ -0,0 +1,274 @@ +# from https://github.com/kaushalmodi/nim_config/blob/master/config.nims + +from macros import error +from ospaths import `/`, splitPath, splitFile +from strutils import `%` +from sequtils import filterIt +from strutils import endsWith + +## Switches +switch("nep1", "on") + +## Constants +const + doOptimize = true + +## Lets +let + root = projectDir() # projectDir() needs nim 0.20.0 (or nim devel as of Tue Oct 16 08:41:09 EDT 2018) + (_, pkgName) = root.splitPath() + srcFile = root / "src" / (pkgName & ".nim") + # pcre + pcreVersion = getEnv("PCREVER", "8.42") + pcreSourceDir = "pcre-" & pcreVersion + pcreArchiveFile = pcreSourceDir & ".tar.bz2" + pcreDownloadLink = "https://downloads.sourceforge.net/pcre/" & pcreArchiveFile + pcreInstallDir = (root / "pcre/") & pcreVersion + # http://www.linuxfromscratch.org/blfs/view/8.1/general/pcre.html + pcreConfigureCmd = ["./configure", "--prefix=" & pcreInstallDir, "--enable-pcre16", "--enable-pcre32", "--disable-shared"] + pcreIncludeDir = pcreInstallDir / "include" + pcreLibDir = pcreInstallDir / "lib" + pcreLibFile = pcreLibDir / "libpcre.a" + # libressl + libreSslVersion = getEnv("LIBRESSLVER", "2.8.1") + libreSslSourceDir = "libressl-" & libreSslVersion + libreSslArchiveFile = libreSslSourceDir & ".tar.gz" + libreSslDownloadLink = "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/" & libreSslArchiveFile + libreSslInstallDir = (root / "libressl/") & libreSslVersion + libreSslConfigureCmd = ["./configure", "--disable-shared", "--prefix=" & libreSslInstallDir] + libreSslLibDir = libreSslInstallDir / "lib" + libreSslLibFile = libreSslLibDir / "libssl.a" + libreCryptoLibFile = libreSslLibDir / "libcrypto.a" + libreSslIncludeDir = libreSslInstallDir / "include/openssl" + # openssl + openSslSeedConfigOsCompiler = "linux-x86_64" + openSslVersion = getEnv("OPENSSLVER", "1.1.1") + openSslSourceDir = "openssl-" & openSslVersion + openSslArchiveFile = openSslSourceDir & ".tar.gz" + openSslDownloadLink = "https://www.openssl.org/source/" & openSslArchiveFile + openSslInstallDir = (root / "openssl/") & openSslVersion + # "no-async" is needed for openssl to compile using musl + # - https://gitter.im/nim-lang/Nim?at=5bbf75c3ae7be940163cc198 + # - https://www.openwall.com/lists/musl/2016/02/04/5 + # -DOPENSSL_NO_SECURE_MEMORY is needed to make openssl compile using musl. + # - https://github.com/openssl/openssl/issues/7207#issuecomment-420814524 + openSslConfigureCmd = ["./Configure", openSslSeedConfigOsCompiler, "no-shared", "no-zlib", "no-async", "-fPIC", "-DOPENSSL_NO_SECURE_MEMORY", "--prefix=" & openSslInstallDir] + openSslLibDir = openSslInstallDir / "lib" + openSslLibFile = openSslLibDir / "libssl.a" + openCryptoLibFile = openSslLibDir / "libcrypto.a" + openSslIncludeDir = openSslInstallDir / "include/openssl" + +## Helper Procs +# https://github.com/kaushalmodi/elnim +proc dollar[T](s: T): string = + result = $s +proc mapconcat[T](s: openArray[T]; sep = " "; op: proc(x: T): string = dollar): string = + ## Concatenate elements of ``s`` after applying ``op`` to each element. + ## Separate each element using ``sep``. + for i, x in s: + result.add(op(x)) + if i < s.len-1: + result.add(sep) + +proc binOptimize(binFile: string) = + ## Optimize size of the ``binFile`` binary. + echo "" + if findExe("strip") != "": + echo "Running 'strip -s' .." + exec "strip -s " & binFile + if findExe("upx") != "": + # https://github.com/upx/upx/releases/ + echo "Running 'upx --best' .." + exec "upx --best " & binFile + +## Tasks +task installPcre, "Installs PCRE using musl-gcc": + if not existsFile(pcreLibFile): + if not existsDir(pcreSourceDir): + if not existsFile(pcreArchiveFile): + exec("curl -LO " & pcreDownloadLink) + exec("tar xf " & pcreArchiveFile) + else: + echo "PCRE lib source dir " & pcreSourceDir & " already exists" + withDir pcreSourceDir: + putEnv("CC", "musl-gcc -static") + exec(pcreConfigureCmd.mapconcat()) + exec("make -j8") + exec("make install") + else: + echo pcreLibFile & " already exists" + setCommand("nop") + +task installLibreSsl, "Installs LIBRESSL using musl-gcc": + if (not existsFile(libreSslLibFile)) or (not existsFile(libreCryptoLibFile)): + if not existsDir(libreSslSourceDir): + if not existsFile(libreSslArchiveFile): + exec("curl -LO " & libreSslDownloadLink) + exec("tar xf " & libreSslArchiveFile) + else: + echo "LibreSSL lib source dir " & libreSslSourceDir & " already exists" + withDir libreSslSourceDir: + # -idirafter /usr/include/ # Needed for linux/sysctl.h + # -idirafter /usr/include/x86_64-linux-gnu/ # Needed for Travis/Ubuntu build to pass, for asm/types.h + putEnv("CC", "musl-gcc -static -idirafter /usr/include/ -idirafter /usr/include/x86_64-linux-gnu/") + putEnv("C_INCLUDE_PATH", libreSslIncludeDir) + exec(libreSslConfigureCmd.mapconcat()) + exec("make -j8 -C crypto") # build just the "crypto" component + exec("make -j8 -C ssl") # build just the "ssl" component + exec("make -C crypto install") + exec("make -C ssl install") + else: + echo libreSslLibFile & " already exists" + setCommand("nop") + +task installOpenSsl, "Installs OPENSSL using musl-gcc": + if (not existsFile(openSslLibFile)) or (not existsFile(openCryptoLibFile)): + if not existsDir(openSslSourceDir): + if not existsFile(openSslArchiveFile): + exec("curl -LO " & openSslDownloadLink) + exec("tar xf " & openSslArchiveFile) + else: + echo "OpenSSL lib source dir " & openSslSourceDir & " already exists" + withDir openSslSourceDir: + # https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html + # -idirafter /usr/include/ # Needed for Travis/Ubuntu build to pass, for linux/version.h, etc. + # -idirafter /usr/include/x86_64-linux-gnu/ # Needed for Travis/Ubuntu build to pass, for asm/types.h + putEnv("CC", "musl-gcc -static -idirafter /usr/include/ -idirafter /usr/include/x86_64-linux-gnu/") + putEnv("C_INCLUDE_PATH", openSslIncludeDir) + exec(openSslConfigureCmd.mapconcat()) + echo "The insecure switch -DOPENSSL_NO_SECURE_MEMORY is needed so that OpenSSL can be compiled using MUSL." + exec("make -j8 depend") + exec("make -j8") + exec("make install_sw") + else: + echo openSslLibFile & " already exists" + setCommand("nop") + +# nim musl foo.nim +task musl, "Builds an optimized static binary using musl": + ## Usage: nim musl [-d:pcre] [-d:libressl|-d:openssl] .. + var + switches: seq[string] + nimFiles: seq[string] + let + numParams = paramCount() + + when defined(libressl) and defined(openssl): + error("Define only 'libressl' or 'openssl', not both.") + + # param 0 will always be "nim" + # param 1 will always be "musl" + for i in 2 .. numParams: + if paramStr(i)[0] == '-': # -d:foo or --define:foo + switches.add(paramStr(i)) + else: + # Non-switch parameters are assumed to be Nim file names. + nimFiles.add(paramStr(i)) + + if nimFiles.len == 0: + error(["The 'musl' sub-command accepts at least one Nim file name", + " Examples: nim musl FILE.nim", + " nim musl FILE1.nim FILE2.nim", + " nim musl -d:pcre FILE.nim", + " nim musl -d:libressl FILE.nim", + " nim musl -d:pcre -d:openssl FILE.nim"].mapconcat("\n")) + + for f in nimFiles: + let + extraSwitches = switches.mapconcat() + (dirName, baseName, _) = splitFile(f) + binFile = dirName / baseName # Save the binary in the same dir as the nim file + nimArgsArray = when doOptimize: + ["c", "-d:musl", "-d:release", "--opt:size", extraSwitches, f] + else: + ["c", "-d:musl", extraSwitches, f] + nimArgs = nimArgsArray.mapconcat() + # echo "[debug] f = " & f & ", binFile = " & binFile + + # Build binary + echo "\nRunning 'nim " & nimArgs & "' .." + selfExec nimArgs + + when doOptimize: + # Optimize binary + binOptimize(binFile) + + echo "\nCreated binary: " & binFile + +task test, "Run tests via 'nim doc' and runnableExamples and tests in tests dir": + let + testDir = root / "tests" + selfExec("doc " & srcFile) + if dirExists(testDir): + let + testFiles = listFiles(testDir).filterIt(it.len >= 5 and it.endsWith(".nim")) + for t in testFiles: + selfExec "c -r " & t + +task docs, "Deploy doc html + search index to public/ directory": + let + deployDir = root / "public" + docOutBaseName = "index" + deployHtmlFile = deployDir / (docOutBaseName & ".html") + genDocCmd = "nim doc --index:on -o:$1 $2" % [deployHtmlFile, srcFile] + deployIdxFile = deployDir / (pkgName & ".idx") + sedCmd = "sed -i 's|" & pkgName & r"\.html|" & docOutBaseName & ".html|' " & deployIdxFile + genTheIndexCmd = "nim buildIndex -o:$1/theindex.html $1" % [deployDir] + deployJsFile = deployDir / "dochack.js" + docHackJsSource = "https://nim-lang.github.io/Nim/dochack.js" # devel docs dochack.js + mkDir(deployDir) + exec(genDocCmd) + exec(sedCmd) # Hack: replace .html with .html in the .idx file + exec(genTheIndexCmd) # Generate theindex.html only after fixing the .idx file + if not fileExists(deployJsFile): + withDir deployDir: + exec("curl -LO " & docHackJsSource) + +## Define Switch Parsing +# -d:musl +when defined(musl): + var + muslGccPath: string + echo " [-d:musl] Building a static binary using musl .." + muslGccPath = findExe("musl-gcc") + echo "debug: " & muslGccPath + if muslGccPath == "": + error("'musl-gcc' binary was not found in PATH.") + switch("passL", "-static") + switch("gcc.exe", muslGccPath) + switch("gcc.linkerexe", muslGccPath) + # -d:pcre + when defined(pcre): + if not existsFile(pcreLibFile): + selfExec "installPcre" # Install PCRE in current dir if pcreLibFile is not found + switch("passC", "-I" & pcreIncludeDir) # So that pcre.h is found when running the musl task + switch("define", "usePcreHeader") + switch("passL", pcreLibFile) + # -d:libressl or -d:openssl + when defined(libressl) or defined(openssl): + switch("define", "ssl") # Pass -d:ssl to nim + when defined(libressl): + let + sslLibFile = libreSslLibFile + cryptoLibFile = libreCryptoLibFile + sslIncludeDir = libreSslIncludeDir + sslLibDir = libreSslLibDir + when defined(openssl): + let + sslLibFile = openSslLibFile + cryptoLibFile = openCryptoLibFile + sslIncludeDir = openSslIncludeDir + sslLibDir = openSslLibDir + + if (not existsFile(sslLibFile)) or (not existsFile(cryptoLibFile)): + # Install SSL in current dir if sslLibFile or cryptoLibFile is not found + when defined(libressl): + selfExec "installLibreSsl" + when defined(openssl): + selfExec "installOpenSsl" + switch("passC", "-I" & sslIncludeDir) # So that ssl.h is found when running the musl task + switch("passL", "-L" & sslLibDir) + switch("passL", "-lssl") + switch("passL", "-lcrypto") # This *has* to come *after* -lssl + switch("dynlibOverride", "libssl") + switch("dynlibOverride", "libcrypto") diff --git a/samples/Nim/filenames/nim.cfg b/samples/Nim/filenames/nim.cfg new file mode 100644 index 0000000000..7ce0d68c37 --- /dev/null +++ b/samples/Nim/filenames/nim.cfg @@ -0,0 +1,270 @@ +# from https://github.com/nim-lang/Nim/blob/devel/config/nim.cfg + +# Configuration file for the Nim Compiler. +# (c) 2017 Andreas Rumpf + +# Feel free to edit the default values as you need. + +# You may set environment variables with +# @putenv "key" "val" +# Environment variables can be accessed like so: +# gcc.path %= "$CC_PATH" + +cc = gcc + +# additional options always passed to the compiler: +--parallel_build: "0" # 0 to auto-detect number of processors + +hint[LineTooLong]=off +#hint[XDeclaredButNotUsed]=off + +# Examples of how to setup a cross-compiler: + +# Cross-compiling for Raspberry Pi. +# (This compiler is available in gcc-arm-linux-gnueabihf package on Ubuntu) +arm.linux.gcc.exe = "arm-linux-gnueabihf-gcc" +arm.linux.gcc.linkerexe = "arm-linux-gnueabihf-gcc" + +# For OpenWRT, you will also need to adjust PATH to point to your toolchain. +mips.linux.gcc.exe = "mips-openwrt-linux-gcc" +mips.linux.gcc.linkerexe = "mips-openwrt-linux-gcc" + + +path="$lib/deprecated/core" +path="$lib/deprecated/pure" +path="$lib/pure/collections" +path="$lib/pure/concurrency" +path="$lib/impure" +path="$lib/wrappers" +path="$lib/wrappers/linenoise" +path="$lib/windows" +path="$lib/posix" +path="$lib/js" +path="$lib/pure/unidecode" +path="$lib/arch" +path="$lib/core" +path="$lib/pure" + +@if nimbabel: + nimblepath="$home/.nimble/pkgs/" + @if not windows: + nimblepath="/opt/nimble/pkgs/" + @else: + # TODO: + @end +@end + +@if release or quick: + obj_checks:off + field_checks:off + range_checks:off + bound_checks:off + overflow_checks:off + assertions:off + stacktrace:off + linetrace:off + debugger:off + line_dir:off + dead_code_elim:on + @if nimHasNilChecks: + nilchecks:off + @end +@end + +@if release: + opt:speed +@end + +@if unix: + @if not bsd or haiku: + # -fopenmp + gcc.options.linker = "-ldl" + gcc.cpp.options.linker = "-ldl" + clang.options.linker = "-ldl" + clang.cpp.options.linker = "-ldl" + tcc.options.linker = "-ldl" + @end + @if bsd: + # BSD got posix_spawn only recently, so we deactivate it for osproc: + define:useFork + # at least NetBSD has problems with thread local storage: + tlsEmulation:on + @end + @if haiku: + # Haiku currently have problems with TLS + # https://dev.haiku-os.org/ticket/14342 + tlsEmulation:on + gcc.options.linker = "-Wl,--as-needed -lnetwork" + gcc.cpp.options.linker = "-Wl,--as-needed -lnetwork" + clang.options.linker = "-Wl,--as-needed -lnetwork" + clang.cpp.options.linker = "-Wl,--as-needed -lnetwork" + tcc.options.linker = "-Wl,--as-needed -lnetwork" + @end +@end + +@if android: + cc = clang + @if termux: + gcc.options.linker = "-landroid-glob" + gcc.cpp.options.linker = "-landroid-glob" + clang.options.linker = "-landroid-glob" + clang.cpp.options.linker = "-landroid-glob" + tcc.options.linker = "-landroid-glob" + @end +@end + +@if nintendoswitch: + cc = "switch_gcc" + switch_gcc.options.linker = "-g -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE" + switch_gcc.cpp.options.linker = "-g -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE" + switch_gcc.options.always = "-g -Wall -O2 -ffunction-sections -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE -D__SWITCH__" + switch_gcc.cpp.options.always = "-g -Wall -O2 -ffunction-sections -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE -D__SWITCH__ -fno-rtti -fno-exceptions -std=gnu++11" +@end + +# Configuration for the Intel C/C++ compiler: +@if windows: + icl.options.speed = "/Ox /arch:SSE2" + icl.options.always = "/nologo" +@end + +# Configuration for the GNU C/C++ compiler: +@if windows: + #gcc.path = r"$nim\dist\mingw\bin" + @if gcc or tcc: + tlsEmulation:on + @end +@end + +@if macosx or freebsd: + cc = clang + tlsEmulation:on + gcc.options.always = "-w" + gcc.cpp.options.always = "-w -fpermissive" +@elif windows: + gcc.options.always = "-w -mno-ms-bitfields" + gcc.cpp.options.always = "-w -fpermissive -mno-ms-bitfields" +@else: + gcc.options.always = "-w" + gcc.cpp.options.always = "-w -fpermissive" +@end + +# Configuration for Objective-C compiler: +# +# Options for GNUStep. GNUStep configuration varies wildly, so you'll probably +# have to add additional compiler and linker flags on a per-project basis. +gcc.objc.options.linker = "-lobjc -lgnustep-base" +llvm_gcc.objc.options.linker = "-lobjc -lgnustep-base" +clang.objc.options.linker = "-lobjc -lgnustep-base" + +# Options for Mac OS X. Mac OS X uses its own Objective-C stack that is +# totally different from GNUStep. +@if macosx: + gcc.objc.options.linker = "-framework Foundation" + llvm_gcc.objc.options.linker = "-framework Foundation" + clang.objc.options.linker = "-framework Foundation" +@end + +# Options for FreeBSD, OpenBSD, NetBSD linker to add locations for searching +# shared libraries. +@if freebsd or openbsd or netbsd: + gcc.options.linker = "-Wl,-rpath=.:/usr/local/lib:/usr/pkg/lib:/usr/X11R6/lib" + gcc.cpp.options.linker = "-Wl,-rpath=.:/usr/local/lib:/usr/pkg/lib:/usr/X11R6/lib" + llvm_gcc.options.linker = "-Wl,-rpath=.:/usr/local/lib:/usr/pkg/lib:/usr/X11R6/lib" + llvm_gcc.cpp.options.linker = "-Wl,-rpath=.:/usr/local/lib:/usr/pkg/lib:/usr/X11R6/lib" + clang.options.linker = "-Wl,-rpath=.:/usr/local/lib:/usr/pkg/lib:/usr/X11R6/lib" + clang.cpp.options.linker = "-Wl,-rpath=.:/usr/local/lib:/usr/pkg/lib:/usr/X11R6/lib" +@end + +# Configuration for the VxWorks +# This has been tested with VxWorks 6.9 only +@if vxworks: + # For now we only support compiling RTPs applications (i.e. no DKMs) + gcc.options.always = "-mrtp -fno-strict-aliasing -D_C99 -D_HAS_C9X -std=c99 -fasm -Wall -Wno-write-strings" + # The linker config must add the VxWorks common library for the selected + # processor which is usually found in: + # "$WIND_BASE/target/lib/usr/lib/PROCESSOR_FAMILY/PROCESSOR_TYPE/common", + # where PROCESSOR_FAMILY and PROCESSOR_TYPE are those supported by the VxWorks + # compiler (e.g. ppc/PPC32 or mips/MIPSI64, etc) + # For now we only support the PowerPC CPU + gcc.options.linker %= "-L $WIND_BASE/target/lib/usr/lib/ppc/PPC32/common -mrtp -fno-strict-aliasing -D_C99 -D_HAS_C9X -std=c99 -fasm -Wall -Wno-write-strings" +@end + +gcc.options.speed = "-O3 -fno-strict-aliasing" +gcc.options.size = "-Os" +@if windows: + gcc.options.debug = "-g3 -O0 -gdwarf-3" +@else: + gcc.options.debug = "-g3 -O0" +@end +gcc.cpp.options.speed = "-O3 -fno-strict-aliasing" +gcc.cpp.options.size = "-Os" +gcc.cpp.options.debug = "-g3 -O0" +#passl = "-pg" + +# Configuration for the LLVM GCC compiler: +llvm_gcc.options.debug = "-g" +llvm_gcc.options.always = "-w" +llvm_gcc.options.speed = "-O2" +llvm_gcc.options.size = "-Os" + +# Configuration for the LLVM CLang compiler: +clang.options.debug = "-g" +clang.options.always = "-w" +clang.options.speed = "-O3" +clang.options.size = "-Os" + +# Configuration for the Visual C/C++ compiler: +vcc.exe = "vccexe.exe" +vcc.cpp.exe = "vccexe.exe" +vcc.linkerexe = "vccexe.exe" +vcc.cpp.linkerexe = "vccexe.exe" + +# set the options for specific platforms: +vcc.options.always = "/nologo" +@if release: + # no debug symbols in release builds +@else: + vcc.options.always %= "${vcc.options.always} /Z7" # Get VCC to output full debug symbols in the obj file +@end +vcc.cpp.options.always %= "${vcc.options.always} /EHsc" +vcc.options.linker = "/nologo /DEBUG /Zi /F33554432" # set the stack size to 32 MiB +vcc.cpp.options.linker %= "${vcc.options.linker}" +@if i386: +vcc.options.always %= "--platform:x86 ${vcc.options.always}" +vcc.cpp.options.always %= "--platform:x86 ${vcc.cpp.options.always}" +vcc.options.linker %= "--platform:x86 ${vcc.options.linker}" +vcc.cpp.options.linker %= "--platform:x86 ${vcc.cpp.options.linker}" +@elif amd64: +vcc.options.always %= "--platform:amd64 ${vcc.options.always}" +vcc.cpp.options.always %= "--platform:amd64 ${vcc.cpp.options.always}" +vcc.options.linker %= "--platform:amd64 ${vcc.options.linker}" +vcc.cpp.options.linker %= "--platform:amd64 ${vcc.cpp.options.linker}" +@elif arm: +vcc.options.always %= "--platform:arm ${vcc.options.always}" +vcc.cpp.options.always %= "--platform:arm ${vcc.cpp.options.always}" +vcc.options.linker %= "--platform:arm ${vcc.options.linker}" +vcc.cpp.options.linker %= "--platform:arm ${vcc.cpp.options.linker}" +@end + +vcc.options.debug = "/Od" +vcc.cpp.options.debug = "/Od" +vcc.options.speed = "/O2" +vcc.cpp.options.speed = "/O2" +vcc.options.size = "/O1" +vcc.cpp.options.size = "/O1" + +# Configuration for the Tiny C Compiler: +tcc.options.always = "-w" + +# Configuration for the Genode toolchain +@if genode: + gcc.path = "/usr/local/genode-gcc/bin" + gcc.cpp.options.always = "-D__GENODE__ -fno-stack-protector" + @if i386 or amd64: + gcc.exe = "genode-x86-gcc" + gcc.cpp.exe = "genode-x86-g++" + @elif arm: + gcc.exe = "genode-arm-gcc" + gcc.cpp.exe = "genode-arm-g++" + @end +@end diff --git a/samples/Nim/foo.nim b/samples/Nim/foo.nim index 58b7f62819..66d5165f11 100644 --- a/samples/Nim/foo.nim +++ b/samples/Nim/foo.nim @@ -1,3 +1,556 @@ -# Hello world program +# from https://github.com/nim-lang/Nim/blob/devel/koch.nim -echo "Hello world!" +# +# +# Maintenance program for Nim +# (c) Copyright 2017 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# +# See doc/koch.txt for documentation. +# + +when defined(gcc) and defined(windows): + when defined(x86): + {.link: "icons/koch.res".} + else: + {.link: "icons/koch_icon.o".} + +when defined(amd64) and defined(windows) and defined(vcc): + {.link: "icons/koch-amd64-windows-vcc.res".} +when defined(i386) and defined(windows) and defined(vcc): + {.link: "icons/koch-i386-windows-vcc.res".} + +import + os, strutils, parseopt, osproc, streams + +import tools / kochdocs + +const VersionAsString = system.NimVersion + +const + HelpText = """ ++-----------------------------------------------------------------+ +| Maintenance program for Nim | +| Version $1| +| (c) 2017 Andreas Rumpf | ++-----------------------------------------------------------------+ +Build time: $2, $3 + +Usage: + koch [options] command [options for command] +Options: + --help, -h shows this help and quits + --latest bundle the installers with a bleeding edge Nimble + --stable bundle the installers with a stable Nimble +Possible Commands: + boot [options] bootstraps with given command line options + distrohelper [bindir] helper for distro packagers + tools builds Nim related tools + nimble builds the Nimble tool +Boot options: + -d:release produce a release version of the compiler + -d:useLinenoise use the linenoise library for interactive mode + (not needed on Windows) + +Commands for core developers: + docs [options] generates the full documentation + csource -d:release builds the C sources for installation + pdf builds the PDF documentation + zip builds the installation zip package + xz builds the installation tar.xz package + testinstall test tar.xz package; Unix only! + tests [options] run the testsuite (run a subset of tests by + specifying a category, e.g. `tests cat async`) + temp options creates a temporary compiler for testing + pushcsource push generated C sources to its repo +Web options: + --googleAnalytics:UA-... add the given google analytics code to the docs. To + build the official docs, use UA-48159761-1 +""" + +template withDir(dir, body) = + let old = getCurrentDir() + try: + setCurrentDir(dir) + body + finally: + setCurrentdir(old) + +proc tryExec(cmd: string): bool = + echo(cmd) + result = execShellCmd(cmd) == 0 + +proc safeRemove(filename: string) = + if existsFile(filename): removeFile(filename) + +proc overwriteFile(source, dest: string) = + safeRemove(dest) + moveFile(source, dest) + +proc copyExe(source, dest: string) = + safeRemove(dest) + copyFile(dest=dest, source=source) + inclFilePermissions(dest, {fpUserExec}) + +const + compileNimInst = "tools/niminst/niminst" + +proc csource(args: string) = + nimexec(("cc $1 -r $3 --var:version=$2 --var:mingw=none csource " & + "--main:compiler/nim.nim compiler/installer.ini $1") % + [args, VersionAsString, compileNimInst]) + +proc bundleNimbleSrc(latest: bool) = + ## bunldeNimbleSrc() bundles a specific Nimble commit with the tarball. We + ## always bundle the latest official release. + if not dirExists("dist/nimble/.git"): + exec("git clone https://github.com/nim-lang/nimble.git dist/nimble") + if not latest: + withDir("dist/nimble"): + exec("git checkout -f stable") + exec("git pull") + +proc bundleNimbleExe(latest: bool) = + bundleNimbleSrc(latest) + # now compile Nimble and copy it to $nim/bin for the installer.ini + # to pick it up: + nimexec("c -d:release --nilseqs:on dist/nimble/src/nimble.nim") + copyExe("dist/nimble/src/nimble".exe, "bin/nimble".exe) + +proc buildNimble(latest: bool) = + # old installations created nim/nimblepkg/*.nim files. We remove these + # here so that it cannot cause problems (nimble bug #306): + if dirExists("bin/nimblepkg"): + removeDir("bin/nimblepkg") + # if koch is used for a tar.xz, build the dist/nimble we shipped + # with the tarball: + var installDir = "dist/nimble" + if not latest and dirExists(installDir) and not dirExists("dist/nimble/.git"): + discard "don't do the git dance" + else: + if not dirExists("dist/nimble/.git"): + if dirExists(installDir): + var id = 0 + while dirExists("dist/nimble" & $id): + inc id + installDir = "dist/nimble" & $id + exec("git clone https://github.com/nim-lang/nimble.git " & installDir) + withDir(installDir): + if latest: + exec("git checkout -f master") + else: + exec("git checkout -f stable") + exec("git pull") + nimexec("c --noNimblePath -p:compiler --nilseqs:on -d:release " & installDir / "src/nimble.nim") + copyExe(installDir / "src/nimble".exe, "bin/nimble".exe) + +proc bundleNimsuggest(buildExe: bool) = + if buildExe: + nimexec("c --noNimblePath -d:release -p:compiler nimsuggest/nimsuggest.nim") + copyExe("nimsuggest/nimsuggest".exe, "bin/nimsuggest".exe) + removeFile("nimsuggest/nimsuggest".exe) + +proc buildVccTool() = + nimexec("c -o:bin/vccexe.exe tools/vccenv/vccexe") + +proc bundleWinTools() = + nimexec("c tools/finish.nim") + copyExe("tools/finish".exe, "finish".exe) + removeFile("tools/finish".exe) + buildVccTool() + nimexec("c -o:bin/nimgrab.exe -d:ssl tools/nimgrab.nim") + nimexec("c -o:bin/nimgrep.exe tools/nimgrep.nim") + when false: + # not yet a tool worth including + nimexec(r"c --cc:vcc --app:gui -o:bin\downloader.exe -d:ssl --noNimblePath " & + r"--path:..\ui tools\downloader.nim") + +proc zip(latest: bool; args: string) = + bundleNimbleExe(latest) + bundleNimsuggest(true) + bundleWinTools() + nimexec("cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" % + [VersionAsString, compileNimInst]) + exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim zip compiler/installer.ini" % + ["tools/niminst/niminst".exe, VersionAsString]) + +proc ensureCleanGit() = + let (outp, status) = osproc.execCmdEx("git diff") + if outp.len != 0: + quit "Not a clean git repository; 'git diff' not empty!" + if status != 0: + quit "Not a clean git repository; 'git diff' returned non-zero!" + +proc xz(latest: bool; args: string) = + ensureCleanGit() + bundleNimbleSrc(latest) + bundleNimsuggest(false) + nimexec("cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" % + [VersionAsString, compileNimInst]) + exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim xz compiler/installer.ini" % + ["tools" / "niminst" / "niminst".exe, VersionAsString]) + +proc buildTool(toolname, args: string) = + nimexec("cc $# $#" % [args, toolname]) + copyFile(dest="bin" / splitFile(toolname).name.exe, source=toolname.exe) + +proc buildTools(latest: bool) = + nimexec "c --noNimblePath -p:compiler -d:release -o:" & ("bin/nimsuggest".exe) & + " nimsuggest/nimsuggest.nim" + + nimexec "c -d:release -o:" & ("bin/nimgrep".exe) & " tools/nimgrep.nim" + when defined(windows): buildVccTool() + + nimexec "c -o:" & ("bin/nimpretty".exe) & " nimpretty/nimpretty.nim" + + buildNimble(latest) + +proc nsis(latest: bool; args: string) = + bundleNimbleExe(latest) + bundleNimsuggest(true) + bundleWinTools() + # make sure we have generated the niminst executables: + buildTool("tools/niminst/niminst", args) + #buildTool("tools/nimgrep", args) + # produce 'nim_debug.exe': + #exec "nim c compiler" / "nim.nim" + #copyExe("compiler/nim".exe, "bin/nim_debug".exe) + exec(("tools" / "niminst" / "niminst --var:version=$# --var:mingw=mingw$#" & + " nsis compiler/installer.ini") % [VersionAsString, $(sizeof(pointer)*8)]) + +proc geninstall(args="") = + nimexec("cc -r $# --var:version=$# --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini $#" % + [compileNimInst, VersionAsString, args]) + +proc install(args: string) = + geninstall() + exec("sh ./install.sh $#" % args) + +when false: + proc web(args: string) = + nimexec("js tools/dochack/dochack.nim") + nimexec("cc -r tools/nimweb.nim $# web/website.ini --putenv:nimversion=$#" % + [args, VersionAsString]) + + proc website(args: string) = + nimexec("cc -r tools/nimweb.nim $# --website web/website.ini --putenv:nimversion=$#" % + [args, VersionAsString]) + + proc pdf(args="") = + exec("$# cc -r tools/nimweb.nim $# --pdf web/website.ini --putenv:nimversion=$#" % + [findNim(), args, VersionAsString], additionalPATH=findNim().splitFile.dir) + +# -------------- boot --------------------------------------------------------- + +proc findStartNim: string = + # we try several things before giving up: + # * bin/nim + # * $PATH/nim + # If these fail, we try to build nim with the "build.(sh|bat)" script. + var nim = "nim".exe + result = "bin" / nim + if existsFile(result): return + for dir in split(getEnv("PATH"), PathSep): + if existsFile(dir / nim): return dir / nim + + when defined(Posix): + const buildScript = "build.sh" + if existsFile(buildScript): + if tryExec("./" & buildScript): return "bin" / nim + else: + const buildScript = "build.bat" + if existsFile(buildScript): + if tryExec(buildScript): return "bin" / nim + + echo("Found no nim compiler and every attempt to build one failed!") + quit("FAILURE") + +proc thVersion(i: int): string = + result = ("compiler" / "nim" & $i).exe + +proc boot(args: string) = + var output = "compiler" / "nim".exe + var finalDest = "bin" / "nim".exe + # default to use the 'c' command: + let bootOptions = if args.len == 0 or args.startsWith("-"): "c" else: "" + let smartNimcache = (if "release" in args: "nimcache/r_" else: "nimcache/d_") & + hostOs & "_" & hostCpu + + copyExe(findStartNim(), 0.thVersion) + for i in 0..2: + echo "iteration: ", i+1 + exec i.thVersion & " $# $# --nimcache:$# compiler" / "nim.nim" % [bootOptions, args, + smartNimcache] + if sameFileContent(output, i.thVersion): + copyExe(output, finalDest) + echo "executables are equal: SUCCESS!" + return + copyExe(output, (i+1).thVersion) + copyExe(output, finalDest) + when not defined(windows): echo "[Warning] executables are still not equal" + +# -------------- clean -------------------------------------------------------- + +const + cleanExt = [ + ".ppu", ".o", ".obj", ".dcu", ".~pas", ".~inc", ".~dsk", ".~dpr", + ".map", ".tds", ".err", ".bak", ".pyc", ".exe", ".rod", ".pdb", ".idb", + ".idx", ".ilk" + ] + ignore = [ + ".bzrignore", "nim", "nim.exe", "koch", "koch.exe", ".gitignore" + ] + +proc cleanAux(dir: string) = + for kind, path in walkDir(dir): + case kind + of pcFile: + var (_, name, ext) = splitFile(path) + if ext == "" or cleanExt.contains(ext): + if not ignore.contains(name): + echo "removing: ", path + removeFile(path) + of pcDir: + case splitPath(path).tail + of "nimcache": + echo "removing dir: ", path + removeDir(path) + of "dist", ".git", "icons": discard + else: cleanAux(path) + else: discard + +proc removePattern(pattern: string) = + for f in walkFiles(pattern): + echo "removing: ", f + removeFile(f) + +proc clean(args: string) = + removePattern("web/*.html") + removePattern("doc/*.html") + cleanAux(getCurrentDir()) + for kind, path in walkDir(getCurrentDir() / "build"): + if kind == pcDir: + echo "removing dir: ", path + removeDir(path) + +# -------------- builds a release --------------------------------------------- + +proc winReleaseArch(arch: string) = + doAssert arch in ["32", "64"] + let cpu = if arch == "32": "i386" else: "amd64" + + template withMingw(path, body) = + let prevPath = getEnv("PATH") + putEnv("PATH", (if path.len > 0: path & PathSep else: "") & prevPath) + try: + body + finally: + putEnv("PATH", prevPath) + + withMingw r"..\mingw" & arch & r"\bin": + # Rebuilding koch is necessary because it uses its pointer size to + # determine which mingw link to put in the NSIS installer. + nimexec "c --cpu:$# koch" % cpu + exec "koch boot -d:release --cpu:$#" % cpu + exec "koch --latest zip -d:release" + overwriteFile r"build\nim-$#.zip" % VersionAsString, + r"web\upload\download\nim-$#_x$#.zip" % [VersionAsString, arch] + +proc winRelease*() = + # Now used from "tools/winrelease" and not directly supported by koch + # anymore! + # Build -docs file: + when true: + buildDocs(gaCode) + withDir "web/upload/" & VersionAsString: + exec "7z a -tzip docs-$#.zip *.html" % VersionAsString + overwriteFile "web/upload/$1/docs-$1.zip" % VersionAsString, + "web/upload/download/docs-$1.zip" % VersionAsString + when true: + csource("-d:release") + when sizeof(pointer) == 4: + winReleaseArch "32" + when sizeof(pointer) == 8: + winReleaseArch "64" + +# -------------- tests -------------------------------------------------------- + +template `|`(a, b): string = (if a.len > 0: a else: b) + +proc tests(args: string) = + # we compile the tester with taintMode:on to have a basic + # taint mode test :-) + nimexec "cc --taintMode:on --opt:speed testament/tester" + # Since tests take a long time (on my machine), and we want to defy Murhpys + # law - lets make sure the compiler really is freshly compiled! + nimexec "c --lib:lib -d:release --opt:speed compiler/nim.nim" + let tester = quoteShell(getCurrentDir() / "testament/tester".exe) + let success = tryExec tester & " " & (args|"all") + if not existsEnv("TRAVIS") and not existsEnv("APPVEYOR"): + exec tester & " html" + if not success: + quit("tests failed", QuitFailure) + +proc temp(args: string) = + proc splitArgs(a: string): (string, string) = + # every --options before the command (indicated by starting + # with not a dash) is part of the bootArgs, the rest is part + # of the programArgs: + let args = os.parseCmdLine a + result = ("", "") + var i = 0 + while i < args.len and args[i][0] == '-': + result[0].add " " & quoteShell(args[i]) + inc i + while i < args.len: + result[1].add " " & quoteShell(args[i]) + inc i + + var output = "compiler" / "nim".exe + var finalDest = "bin" / "nim_temp".exe + # 125 is the magic number to tell git bisect to skip the current + # commit. + let (bootArgs, programArgs) = splitArgs(args) + let nimexec = findNim() + exec(nimexec & " c -d:debug --debugger:native " & bootArgs & " compiler" / "nim", 125) + copyExe(output, finalDest) + if programArgs.len > 0: exec(finalDest & " " & programArgs) + +proc xtemp(cmd: string) = + let d = getAppDir() + copyExe(d / "bin" / "nim".exe, d / "bin" / "nim_backup".exe) + try: + withDir(d): + temp"" + copyExe(d / "bin" / "nim_temp".exe, d / "bin" / "nim".exe) + exec(cmd) + finally: + copyExe(d / "bin" / "nim_backup".exe, d / "bin" / "nim".exe) + +proc pushCsources() = + if not dirExists("../csources/.git"): + quit "[Error] no csources git repository found" + csource("-d:release") + let cwd = getCurrentDir() + try: + copyDir("build/c_code", "../csources/c_code") + copyFile("build/build.sh", "../csources/build.sh") + copyFile("build/build.bat", "../csources/build.bat") + copyFile("build/build64.bat", "../csources/build64.bat") + copyFile("build/makefile", "../csources/makefile") + + setCurrentDir("../csources") + for kind, path in walkDir("c_code"): + if kind == pcDir: + exec("git add " & path / "*.c") + exec("git commit -am \"updated csources to version " & NimVersion & "\"") + exec("git push origin master") + exec("git tag -am \"Version $1\" v$1" % NimVersion) + exec("git push origin v$1" % NimVersion) + finally: + setCurrentDir(cwd) + +proc testUnixInstall(cmdLineRest: string) = + csource("-d:release " & cmdLineRest) + xz(false, cmdLineRest) + let oldCurrentDir = getCurrentDir() + try: + let destDir = getTempDir() + copyFile("build/nim-$1.tar.xz" % VersionAsString, + destDir / "nim-$1.tar.xz" % VersionAsString) + setCurrentDir(destDir) + execCleanPath("tar -xJf nim-$1.tar.xz" % VersionAsString) + setCurrentDir("nim-$1" % VersionAsString) + execCleanPath("sh build.sh") + # first test: try if './bin/nim --version' outputs something sane: + let output = execProcess("./bin/nim --version").splitLines + if output.len > 0 and output[0].contains(VersionAsString): + echo "Version check: success" + execCleanPath("./bin/nim c koch.nim") + execCleanPath("./koch boot -d:release", destDir / "bin") + # check the docs build: + execCleanPath("./koch docs", destDir / "bin") + # check nimble builds: + execCleanPath("./koch --latest tools") + # check the tests work: + putEnv("NIM_EXE_NOT_IN_PATH", "NOT_IN_PATH") + execCleanPath("./koch tests", destDir / "bin") + #execCleanPath("./koch tests cat newconfig", destDir / "bin") + else: + echo "Version check: failure" + finally: + setCurrentDir oldCurrentDir + +proc valgrind(cmd: string) = + # somewhat hacky: '=' sign means "pass to valgrind" else "pass to Nim" + let args = parseCmdLine(cmd) + var nimcmd = "" + var valcmd = "" + for i, a in args: + if i == args.len-1: + # last element is the filename: + valcmd.add ' ' + valcmd.add changeFileExt(a, ExeExt) + nimcmd.add ' ' + nimcmd.add a + elif '=' in a: + valcmd.add ' ' + valcmd.add a + else: + nimcmd.add ' ' + nimcmd.add a + exec("nim c" & nimcmd) + let supp = getAppDir() / "tools" / "nimgrind.supp" + exec("valgrind --suppressions=" & supp & valcmd) + +proc showHelp() = + quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)), + CompileDate, CompileTime], QuitSuccess) + +when isMainModule: + var op = initOptParser() + var latest = false + var stable = false + while true: + op.next() + case op.kind + of cmdLongOption, cmdShortOption: + case normalize(op.key) + of "latest": latest = true + of "stable": stable = true + else: showHelp() + of cmdArgument: + case normalize(op.key) + of "boot": boot(op.cmdLineRest) + of "clean": clean(op.cmdLineRest) + of "doc", "docs": buildDocs(op.cmdLineRest) + of "doc0", "docs0": + # undocumented command for Araq-the-merciful: + buildDocs(op.cmdLineRest & gaCode) + of "pdf": buildPdfDoc(op.cmdLineRest, "doc/pdf") + of "csource", "csources": csource(op.cmdLineRest) + of "zip": zip(latest, op.cmdLineRest) + of "xz": xz(latest, op.cmdLineRest) + of "nsis": nsis(latest, op.cmdLineRest) + of "geninstall": geninstall(op.cmdLineRest) + of "distrohelper": geninstall() + of "install": install(op.cmdLineRest) + of "testinstall": testUnixInstall(op.cmdLineRest) + of "test", "tests": tests(op.cmdLineRest) + of "temp": temp(op.cmdLineRest) + of "xtemp": xtemp(op.cmdLineRest) + of "wintools": bundleWinTools() + of "nimble": + if stable: buildNimble(false) + else: buildNimble(existsDir(".git") or latest) + of "nimsuggest": bundleNimsuggest(buildExe=true) + of "tools": + if stable: buildTools(false) + else: buildTools(existsDir(".git") or latest) + of "pushcsource", "pushcsources": pushCsources() + of "valgrind": valgrind(op.cmdLineRest) + else: showHelp() + break + of cmdEnd: break diff --git a/samples/Nim/nimfix.nim.cfg b/samples/Nim/nimfix.nim.cfg new file mode 100644 index 0000000000..5d1f3befcf --- /dev/null +++ b/samples/Nim/nimfix.nim.cfg @@ -0,0 +1,19 @@ +# from: https://github.com/nim-lang/Nim/blob/27b081d1f77604ee47c886e69dbc52f53ea3741f/compiler/nimfix/nimfix.nim.cfg + +# Special configuration file for the Nim project +# gc:markAndSweep + +hint[XDeclaredButNotUsed]:off +path:"$projectPath/.." + +path:"$lib/packages/docutils" +path:"$nim" + +define:useStdoutAsStdmsg +symbol:nimfix +define:nimfix + +cs:partial +#define:useNodeIds +define:booting +define:noDocgen diff --git a/samples/Nim/zip.nimble b/samples/Nim/zip.nimble new file mode 100644 index 0000000000..de43c7e93f --- /dev/null +++ b/samples/Nim/zip.nimble @@ -0,0 +1,20 @@ +# from https://github.com/nim-lang/Nim/blob/devel/tests/deps/zip-0.2.1/zip.nimble + +# Package + +version = "0.2.1" +author = "Anonymous" +description = "Wrapper for the zip library" +license = "MIT" + +skipDirs = @["tests"] + +# Dependencies + +requires "nim >= 0.10.0" + +task tests, "Run lib tests": + withDir "tests": + exec "nim c -r ziptests" + exec "nim c -r zlibtests" + exec "nim c -r gziptests"