magiblot / tvision

A modern port of Turbo Vision 2.0, the classical framework for text-based user interfaces. Now cross-platform and with Unicode support.
Other
1.99k stars 150 forks source link

Convert variable definitions in *.h files into enums #131

Closed Kh-Oleg closed 8 months ago

Kh-Oleg commented 8 months ago

Convert variable definitions in *.h files into enums to avoid duplicated symbols in resulting binaries.

This reduces the sizes of resulting binaries by almost 30%: image

magiblot commented 8 months ago

Hi Oleg!

Thank you very much for this pull request! I appreciate the effort.

I would like to note that, in this case, the size overhead is not because of bad programming, but because of the compiler. In C++, const variables have internal linkage, so the compiler should optimize them out. This issue is therefore not related to code generation, but to debug information.

To demonstrate this, I compared the files generated by different compilers, with and without debug information:

GCC x86_64

build-gcc-debug-Kh-Oleg:
-rw-r--r--  1 magiblot magiblot 3981244 ene  6 19:42 libtvision.a
build-gcc-debug-magiblot:
-rw-r--r--  1 magiblot magiblot 5927452 ene  6 19:42 libtvision.a

build-gcc-release-Kh-Oleg:
-rw-r--r--  1 magiblot magiblot 2017934 ene  6 19:43 libtvision.a
build-gcc-release-magiblot:
-rw-r--r--  1 magiblot magiblot 2017934 ene  6 19:43 libtvision.a

build-gcc-relwithdebinfo-Kh-Oleg:
-rw-r--r--  1 magiblot magiblot 12517910 ene  6 19:43 libtvision.a
build-gcc-relwithdebinfo-magiblot:
-rw-r--r--  1 magiblot magiblot 13682190 ene  6 19:43 libtvision.a

Clang x86_64

build-clang-debug-Kh-Oleg:
-rw-r--r--  1 magiblot magiblot 3688444 ene  6 19:56 libtvision.a
build-clang-debug-magiblot:
-rw-r--r--  1 magiblot magiblot 3688452 ene  6 19:56 libtvision.a

build-clang-release-Kh-Oleg:
-rw-r--r--  1 magiblot magiblot 1837864 ene  6 19:56 libtvision.a
build-clang-release-magiblot:
-rw-r--r--  1 magiblot magiblot 1837864 ene  6 19:56 libtvision.a

build-clang-relwithdebinfo-Kh-Oleg:
-rw-r--r--  1 magiblot magiblot 6961522 ene  6 19:57 libtvision.a
build-clang-relwithdebinfo-magiblot:
-rw-r--r--  1 magiblot magiblot 6595058 ene  6 19:57 libtvision.a

MSVC x86_64 (Windows)

build-msvc-Kh-Oleg/Debug:
-rw-r--r-- 1 magiblot magiblot 10550704 ene  6 20:19 tvision-debug.lib
-rw-r--r-- 1 magiblot magiblot  3117056 ene  6 20:19 tvision-debug.pdb
build-msvc-magiblot/Debug:
-rw-r--r-- 1 magiblot magiblot 10661868 ene  6 20:11 tvision-debug.lib
-rw-r--r-- 1 magiblot magiblot  3100672 ene  6 20:11 tvision-debug.pdb

build-msvc-Kh-Oleg/Release:
-rw-r--r-- 1 magiblot magiblot 3178700 ene  6 20:19 tvision.lib
build-msvc-magiblot/Release:
-rw-r--r-- 1 magiblot magiblot 3183046 ene  6 20:12 tvision.lib

build-msvc-Kh-Oleg/RelWithDebInfo:
-rw-r--r-- 1 magiblot magiblot 6289172 ene  6 20:20 tvision-relwithdebinfo.lib
-rw-r--r-- 1 magiblot magiblot 3059712 ene  6 20:20 tvision-relwithdebinfo.pdb
build-msvc-magiblot/RelWithDebInfo:
-rw-r--r-- 1 magiblot magiblot 6401918 ene  6 20:13 tvision-relwithdebinfo.lib
-rw-r--r-- 1 magiblot magiblot 3051520 ene  6 20:13 tvision-relwithdebinfo.pdb

Without debug information, the binary size is exactly the same whether this patch is applied or not with GCC and Clang. With MSVC the size is almost the same.

With debug information, the change in binary size is pretty much unimportant with Clang or MSVC. It is only when using GCC that the resulting binaries are absolutely oversized and that applying this patch makes a huge difference.

Given that this patch does not make a difference in non-debug builds, I do not consider this change to be necessary. But since the size reduction with GCC is still an advantage, I believe the change would be worth it anyway as long as there are no downsides.

However, there's an issue with this patch: it breaks the build with Borland C++, which doesn't support specifying an underlying type for enums. We would have to use plain enums only, but this could break something since the semantics would change. Therefore, I'm not sure what we should do...

Cheers.

paule32 commented 8 months ago

Hi, I use asmjit, which you can use, to optimize your C++ Assembler generated Code. So, it is highly optimized. Then you can use this Code, and have very speedy Application's. Okay... maybe you have a little bit payload. But, the asmjit has on my System a DLL of about 300 KByte's in size. And it is platform neutral - so you can use it on Windows, Linux, and ARM - in 32-Bit, and 64-Bit.

Happy Codeing paule32

paule32 commented 8 months ago

Hi, After the compilation of your Application, you can use the Application "strip.exe" It is part of the GNU C/C++, and FPC Package. With this Application, you can "strip" many things out of your binaries. Which results in very tiny .exe files - if you don't need to debug the binaries, and have compile your Application with debug Option's like -g gdb strip.exe cut's all debug, and debug info (dwarf) out.

Next ... I don't remember where I have the Tool UPX (sourceforge.net ?). This Tool can be used to shrink the "stripped" .executables or .dll/.so files again, by a ratio measure by 20 - 25. UPX don't need any other DLL File's - it comes with a little payload - but you would love it !!! UPX is available for MS-DOS, Windows, Linux, MacOS (with source code).

Happy packing paule32

Kh-Oleg commented 8 months ago

hi @magiblot,

I see. The compilers seems to be clever enough to optimize out instances of const variables. I still believe that it's better to instruct compilers explicitly to not allocate place in executable files at all (enum or define or inline const in C++17 ), rather than rely on optimization, but in the given project it doesn't make much difference.

So, I'm fine if the PR will be rejected, it's up to you.

May I ask you also, why are you so concerned about backward compatibility with DOS and Borland C++? How would you like to develop this project further?

I think, there is a need in easy-to-use TUI SDK, a modern and easy to use as a replacement for archaic ncurses, kind of Qt for terminal applications. Your port of TurboVision would be a good starting point to go further, but it will require to sacrifice backward compatibility with old platforms.

What do you think?

magiblot commented 7 months ago

Hi Oleg!

Excuse me for the late reply.

When I started this project in the last days of 2018, I also got the impression that most of the Internet was suggesting to use Ncurses (or even worse: termios.h 😱) as the starting point for a terminal application. No wonder why the most popular Unix terminal applications were so ugly.

Compared to Ncurses, there's no doubt Turbo Vision enables you to create complex UIs at a much smaller effort (I do not mean to criticize Ncurses by saying this; Ncurses is a very important piece of software but it lies at a much lower level of abstraction than needed here). However, that doesn't mean that Turbo Vision is easy or comfortable to use. I strongly believe it isn't. It has a few severe design flaws, such as having a class hierarchy which requires you to learn quite a bit about the internal details of the classes you extend. It's also pretty easy to run into memory safety issues if you have not yet figured out the intricate details of how some things work.

So, if Turbo Vision was to be taken as a starting point for a solid, modern and easy-to-use TUI SDK, it would clearly require a major redesign and lots of new features.

The thing is, even though my programming experience allows me to realize the flaws in Turbo Vision, my inexperience in UI programming makes me unable to design an alternative that is up to the task, let alone maintain it. Additionally, TUI libraries focused on ease of use have proliferated in the last few years.

Therefore, I do not see the need, and it would certainly not be convenient to undertake such a task myself.

On the topic of backward compatibility, it is clear that it is incompatible with evolving Turbo Vision into what you are talking about. However, as I explained, I never intended to evolve Turbo Vision that far. So, I thought it would be good to at least keep it backward compatible; I think it makes sense in this context. It is also a bit of a self-imposed challenge which I like. This doesn't of course mean that Turbo Vision can't be improved at all.

Thus, I currently see this project in two ways: as a TUI library for daring people, and as a retroprogramming project.