Closed plicit closed 1 year ago
Thank you for reporting. I fixed errors in openGL4kGen.
Great, thanks! That's a neat fix with sugar collect.
minimumGLTriangle.nim
now compiles the default version correctly, but Crinkler breaks the danger
version:
default build = 226 KB (and works)
danger Crinkler build = 875 Bytes (nothing happens when running it -- it has no PE sections)
So, Crinkler 2.3 (Jul 21 2020) is either broken or incompatible with Visual Studio 2022 obj files (the VS 2015 installer gives me an error that it can't find BuildTools_MSBuild.msi when installing).
I tried Nim compiling with --cc:gcc
but got a bunch of error: static assertion failed
errors.
I then modified src/config.nims
to see what danger
would look like without Crinkler, but I couldn't get the switches right since Nim seems to be linking with libcMT now:
# nim c -d:danger minimumGLTriangle.nim
Hint: used config file '[...]\config\nim.cfg' [Conf]
Hint: used config file '[...]\config\config.nims' [Conf]
Hint: used config file '[...]\src\config.nims' [Conf]
Hint: used config file '[...]\src\minimumGLTriangle.nims' [Conf]
.............................................
CC: minimumGLTriangle.nim
@mminimumGLTriangle.nim.c
[...]\@mminimumGLTriangle.nim.c(94): warning C4133: 'function': incompatible types - from 'const tyObject_PIXELFORMATDESCRIPTOR__GBn82Vqxouo39b0CD3oAxsw *' to 'const PIXELFORMATDESCRIPTOR *'
[...]\@mminimumGLTriangle.nim.c(96): warning C4133: 'function': incompatible types - from 'const tyObject_PIXELFORMATDESCRIPTOR__GBn82Vqxouo39b0CD3oAxsw *' to 'const PIXELFORMATDESCRIPTOR *'
Hint: [Link]
Microsoft (R) C/C++ Optimizing Compiler Version 19.36.32534 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
Microsoft (R) Incremental Linker Version 14.36.32534.0 Copyright (C) Microsoft Corporation. All rights reserved.
/out:@mC@c@s_scoop@sapps@snim@scurrent@slib@ssystem@sio.nim.c.exe user32.lib kernel32.lib Gdi32.lib Opengl32.lib /SUBSYSTEM:WINDOWS /entry:WinMainCRTStartup /OUT:D:\data\dev\nim\demotomohiro_nim-4k-intro-sample\src\minimumGLTriangle.exe [...]\@mC@c@s_scoop@sapps@snim@scurrent@slib@ssystem@sio.nim.c.obj [...]\@mC@c@s_scoop@sapps@snim@scurrent@slib@ssystem.nim.c.obj [...]\@mopenGL4k2.nim.c.obj [...]\@mminimumGLTriangle.nim.c.obj
LIBCMT.lib(exe_winmain.obj) : error LNK2019: unresolved external symbol _WinMain@16 referenced in function "int cdecl scrt_common_main_seh(void)" (?__scrt_common_main_seh@@YAHXZ) [...]\src\minimumGLTriangle.exe : fatal error LNK1120: 1 unresolved externals
Error: execution of an external program failed: 'vccexe.exe
[...]\@mC@c@s_scoop@sapps@snim@scurrent@slib@ssystem@sio.nim.c.obj
[...]\@mC@c@s_scoop@sapps@snim@scurrent@slib@ssystem.nim.c.obj
[...]\@mopenGL4k2.nim.c.obj
[...]\@mminimumGLTriangle.nim.c.obj /link user32.lib kernel32.lib Gdi32.lib Opengl32.lib /SUBSYSTEM:WINDOWS /entry:WinMainCRTStartup /OUT:[...]\minimumGLTriangle.exe'
- Of course, the `csrc` build = 4 KB without crinkler and works
Seems VS 2019 works but VS 2022 doesn't with Crinkler: https://github.com/runestubbe/Crinkler/issues/13
If minimumGLTriangle.nim
doesn't compile well, try compiling minimum.nim
.
minimum.nim
is simpler than minimumGLTriangle.nim
and easier to find a problem.
Make sure Nim calls C compiler for 32bit x86 CPU.
Crinkler doesn't support x64 and people creating 4k intro or small size intro don't create 64bit binary as it likely larger than 32bit binary.
Nim should call 32bit one when --cc:vcc
and --cpu:i386
options are set.
You can check how Nim calls backend C compiler by adding --listcmd
option.
Thanks for your help! Sorry I missed that issue on Crinkler -- unfortunately, it still doesn't work with VS2019 (I even uninstalled all other VS versions). I'll try VS2015 once I figure out why its installer is failing.
Does Crinkler 2.3 work for you with minimum.c
and VS2019 build tools?
minimum.c
:
#include <windows.h>
void WinMainCRTStartup(void) {
MessageBoxA(0, "foobar", "title", 0);
}
Build:
Microsoft Windows [Version 10.0.19045.2965]
(c) Microsoft Corporation. All rights reserved.
D:\dev> "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars32.bat"
**********************************************************************
** Visual Studio 2019 Developer Command Prompt v16.11.27
** Copyright (c) 2021 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x86'
D:\dev> cl /c minimum.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30151 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
minimum.c
D:\dev> crinkler /subsystem:windows /OUT:minimum_crinkler.exe user32.lib kernel32.lib minimum.obj
Crinkler 2.3 (Jul 21 2020) (c) 2005-2020 Aske Simon Christensen & Rune Stubbe
Target: minimum_crinkler.exe
Tiny compressor: NO
Tiny import: NO
Subsystem type: WINDOWS
Large address aware: NO
Compression mode: SLOW
Saturate counters: NO
Hash size: 500 MB
Hash tries: 100
Order tries: 0
Reuse mode: OFF (no file specified)
Report: NONE
Transforms: NONE
Replace DLLs: NONE
Fallback DLLs: NONE
Range DLLs: NONE
Exports: NONE
Loading user32.lib...
Loading kernel32.lib...
Loading minimum.obj...
Linking...
Uncompressed size of code: 163
Uncompressed size of data: 27
|-- Estimating models for code ----------------------------|
............................................................ 0m00s
Estimated compressed size of code: 132.71
|-- Estimating models for data ----------------------------|
............................................................ 0m00s
Estimated compressed size of data: 20.95
Ideal compressed size of code: 132.71
Ideal compressed size of data: 20.95
Ideal compressed total size: 153.66
|-- Optimizing hash table size ----------------------------|
............................................................ 0m00s
Real compressed total size: 154
Bytes lost to hashing: 0.34
Output file: minimum_crinkler.exe
Final file size: 442
time spent: 0m00s
minimum_crinkler.exe
seems to start but does nothing and then exits. If I change the subsystem to console, it opens a console window, pauses and then exits.
Regarding your Nim-4k, the "release" size of the .exes are ~100 KB, so I doubt Crinkler could actually get that down to 4k.
My package setup is roughly:
choco upgrade visualstudio2019buildtools --package-parameters "--includeRecommended"
choco upgrade visualstudio2019-workload-vctools
scoop install crinkler
And here is a .bat build script that clones your repo and downloads OpenGL headers and cacert.pem needed for openGL4kGen.exe and then builds a few .exe:
build-nim4kintro.bat
:
SetLocal EnableDelayedExpansion
@echo --------------------------------
@echo -- Setup environment:
@echo --------------------------------
set NIM4K=%~dp0\nim-4k-intro-sample
IF NOT EXIST "!NIM4K!" (
git clone https://github.com/demotomohiro/nim-4k-intro-sample
@echo on
)
pushd "!NIM4K!"
@echo --------------------------------
@echo -- Setup Visual Studio 2019 32-bit
@echo --------------------------------
set OPENGL=!NIM4K!\OpenGL
WHERE cl.exe
IF %ERRORLEVEL% NEQ 0 (
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars32.bat"
@echo on
set INCLUDE=!OPENGL!;!INCLUDE!
@echo INCLUDE = !INCLUDE!
@rem LIB should already be set by vcvars32
@rem set LIB=c:\Program Files (x86)\Windows Kits\10\Lib\10.0.20348.0\um\x86;%LIB%
)
@echo --------------------------------
@echo -- Download OpenGL headers
@echo --------------------------------
IF NOT EXIST "!OPENGL!\GL\glext.h" (
@echo DOWNLOADING OPENGL
mkdir "!OPENGL!\GL"
pushd "!OPENGL!\GL"
curl -LO https://registry.khronos.org/OpenGL/api/GL/glext.h
curl -LO https://registry.khronos.org/OpenGL/api/GL/wglext.h
curl -LO https://registry.khronos.org/OpenGL/api/GL/glxext.h
curl -LO https://registry.khronos.org/OpenGL/api/GL/glcorearb.h
popd
mkdir "!OPENGL!\KHR"
pushd "!OPENGL!\KHR"
curl -LO https://registry.khronos.org/EGL/api/KHR/khrplatform.h
popd
)
@echo --------------------------------
@echo -- Build openGL4kGen and generate files
@echo --------------------------------
IF NOT EXIST "!NIM4K!\tools\openGL4kGen\openGL4kGen.exe" (
pushd "tools\openGL4kGen"
@rem cacert.pem is a requirement
curl -LO https://curl.se/ca/cacert.pem
nim c -d:ssl openGL4kGen.nim
openGL4kGen.exe > ..\..\src\openGL4k2.nim
popd
)
@echo --------------------------------
@echo -- Build some csrc .exe
@echo --------------------------------
pushd csrc
@rem these use Crinkler and are broken:
call minimum_build.bat
call minimumGLTriangle_build.bat
@rem minimumGLTriangle_build.bat created triangle.vs.h needed to build, so we don't have to:
@rem nim e glslheader.nims ..\shaders\triangle.vs ..\shaders\triangle.fs
@echo Build a .exe from C without Crinkler (works 4k)
cl.exe /nologo /O1 /Ob2 /Oi /Os minimumGLTriangle.c /link user32.lib kernel32.lib Gdi32.lib Opengl32.lib /SUBSYSTEM:WINDOWS /entry:WinMainCRTStartup /out:minimumGLTriangle.exe
@rem Crinkler would break our .exe, too:
@rem crinkler /OUT:minimumGLTriangle_c.exe /SUBSYSTEM:WINDOWS /entry:WinMainCRTStartup user32.lib kernel32.lib Gdi32.lib Opengl32.lib minimumGLTriangle.obj
popd
@echo --------------------------------
@echo -- Build some src .exe
@echo --------------------------------
pushd src
@rem works ~209 KB:
nim c minimum.nim
nim c minimumGLTriangle.nim
@rem works ~138 KB:
nim c -d:release --out:minimum.release.exe minimum.nim
nim c -d:release --out:minimumGLTriangle.release.exe minimumGLTriangle.nim
@rem broken 442 bytes and 875 bytes:
nim c -d:danger --out:minimum.danger.crinkled minimum.nim
nim c -d:danger --out:minimumGLTriangle.danger.crinkled minimumGLTriangle.nim
popd
rem exit NIM4K directory
popd
@echo --------------------------------
@echo -- DONE
@echo --------------------------------
Like Nim was used to write malware and executables compiled with Nim were detected by antivirus softwares even if it is not virus, Crinkler was used by malware writers and executables generated by Crinkler were sometimes detected by antivirus softwares.
Your antivirus software might stop running minimum_crinkler.exe
.
When compiled without -d:danger, src/config.nims
doesn't change linker settings, and a linker in visual studio is called by Nim.
In that case, C standard library/runtime is linked and generated executable become bigger.
When compiled with -d:danger, crinker is called and C standard library/runtime is not linked.
It turns out that Nim wants to link the CRT lib regardless of -d:danger
due to unresolved external symbols in lib\system\io.nim
:
__setmode
___acrt_iob_func
__fileno
However, lib\system\io.nim
only loads those symbols when windows
is defined AND nimscript
is NOT defined, so I tried defining nimscript
and it worked!
nim c --listcmd -d:release -d:nimscript -d:danger minimumGLTriangle.nim
That minimumGLTriangle.exe
is under 4k even without crinkler (which is broken on the Win10's that I've tried). Ideally, Nim should have a flag for excluding the CRT rather than abusing nimscript
, but at least there is a way.
Here's my config.nims
for posterity:
--cc:vcc
--d:noAutoGLerrorCheck
--cpu:i386
--os:standalone
--gc:none
--dynlibOverrideAll
--noMain
--opt:size
#switch("d", "StandaloneHeapSize=0")
switch("d", "windows")
put "vcc.options.always", "/nologo /Ob2 /Oi /Os /GS-"
put "vcc.options.linker", "/link /SUBSYSTEM:WINDOWS /entry:WinMainCRTStartup /nodefaultlib"
if not existsFile("openGL4k2.nim"):
withDir "../tools/openGL4kGen":
selfExec("c -d:ssl openGL4kGen.nim")
exec("openGL4kGen.exe -o=../../src/openGL4k2.nim")
Thanks for all your help! :)
Hi and thanks for sharing your code! :)
I just started exploring Nim and tried your 4k-intro but it turns out that
specialWords
no longer exists in Nim's compiler/wordrecg, so compilation fails:openGL4kGen.nim(91, 7) Error: undeclared identifier: 'specialWords'
https://github.com/demotomohiro/nim-4k-intro-sample/blob/master/tools/openGL4kGen/openGL4kGen.nim#L89-L91With some experimenting, I figured out a way to generate a Sequence of the same strings (I think), though it executes at runtime:
Do you know if there is a better way to create a ranged subset of an
enum
s strings at compiletime in Nim?