Skip to content

VC++ on v12+ builds bloated addon binaries. #29501

Closed
@simonbuchan

Description

  • Version: v12.0.0
  • Platform: Windows 10 64-bit
  • Subsystem:

Opening this as a node bug, rather than a node-gyp bug, as it's specific to the target version of node, thus presumably to do with the files node-gyp fetches from nodejs.org/dist/...

I've been maintaining a native module available here for low-level access to the windows notification icon and closely related APIs, and recently found that my .node binary size increased from ~300kB to ~1MB. Since I'm only targeting windows and using N-API, I prebuild the binary and include that in my package so users don't have to install build tools, and I wanted to debug why this increase happened.

After some debugging, I found that this is due to building against node v12.0.0 up:

> yarn rebuild --target v10.16.3
...
>dir notify_icon.node
...
2019-09-09  19:56           377,856 notify_icon.node
...
> yarn rebuild --target v11.13.0
...
>dir notify_icon.node
...
2019-09-09  19:56           377,856 notify_icon.node
...
> yarn rebuild --target v12.0.0
...
>dir notify_icon.node
...
2019-09-09  18:20         1,122,304 notify_icon.node
...
> yarn rebuild --target v12.10.0
...
>dir notify_icon.node
...
2019-09-09  18:20         1,122,304 notify_icon.node
...

Attached is the output of Sizer, which seems to give the most readable output for windows, the output seems to be identical for all before v12 and for all from 12:

Notably, when diffing:

@@ -1,96 +1,202 @@
 Functions by size (kilobytes, min 0.50):
-    1.69: napi_get_cb_info<MenuObject*,int,int>                                            menu-object.obj                          napi_get_cb_info<MenuObject*,int,int>
-    1.69: napi_get_cb_info<MenuObject*,int,menu_item>                                      menu-object.obj                          napi_get_cb_info<MenuObject*,int,menu_item>
-    1.69: napi_get_cb_info<NotifyIconObject*,notify_icon_object_options>                   notify-icon-object.obj                   napi_get_cb_info<NotifyIconObject*,notify_icon_object_options>
-    1.68: napi_get_cb_info<void,icon_size_t,std::optional<unsignedint>,std::optional<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>>> icon-object.obj                          enum napi_status __cdecl napi_get_cb_info<void,struct icon_size_t,class std::optional<unsigned int>,class std::optional<class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> > > >(struct napi_env__ * __ptr64,struct napi_callback_info__ * __ptr64,void * __ptr64,...
-    1.66: napi_register_module_v1                                                          module.obj                               napi_register_module_v1
-    1.66: napi_get_cb_info<MenuObject*,int>                                                menu-object.obj                          napi_get_cb_info<MenuObject*,int>
+    4.54: __acrt_fltout                                                                    cfout.obj                                __acrt_fltout
+    4.32: convert_to_fos_high_precision<double>                                            cfout.obj                                convert_to_fos_high_precision<double>
+    3.38: UnDecorator::composeDeclaration                                                  undname.obj                              private: static class DName __cdecl UnDecorator::composeDeclaration(class DName const & __ptr64)
+    1.92: UnDecorator::getDataIndirectType                                                 undname.obj                              private: static class DName __cdecl UnDecorator::getDataIndirectType(class DName const & __ptr64,char const * __ptr64,class DName const & __ptr64,int)
+    1.85: UnDecorator::getOperatorName                                                     undname.obj                              private: static class DName __cdecl UnDecorator::getOperatorName(bool,bool * __ptr64)
+    1.83: __crt_strtox::parse_integer<unsigned__int64,__crt_strtox::c_string_character_source<wchar_t>> atox.obj                                 unsigned __int64 __cdecl __crt_strtox::parse_integer<unsigned __int64,class __crt_strtox::c_string_character_source<wchar_t> >(struct __crt_locale_pointers * __ptr64 const,class __crt_strtox::c_string_character_source<wchar_t>,int,bool)
+    1.77: napi_get_cb_info<void,napi_buffer_info>                                          reg-icon-stream.obj                      enum napi_status __cdecl napi_get_cb_info<void,struct napi_buffer_info>(struct napi_env__ * __ptr64,struct napi_callback_info__ * __ptr64,void * __ptr64,void * __ptr64 * __ptr64,int,struct napi_buffer_info * __ptr64)
+    1.66: __crt_strtox::parse_integer<unsignedlong,__crt_strtox::c_string_character_source<wchar_t>> atox.obj                                 unsigned long __cdecl __crt_strtox::parse_integer<unsigned long,class __crt_strtox::c_string_character_source<wchar_t> >(struct __crt_locale_pointers * __ptr64 const,class __crt_strtox::c_string_character_source<wchar_t>,int,bool)
     1.61: Concurrency::details::UMS::Initialize                                            UMSWrapper.obj                           public: static void __cdecl Concurrency::details::UMS::Initialize(void)
-    1.58: napi_get_cb_info<void,unsignedint,icon_size_t>                                   icon-object.obj                          enum napi_status __cdecl napi_get_cb_info<void,unsigned int,struct icon_size_t>(struct napi_env__ * __ptr64,struct napi_callback_info__ * __ptr64,void * __ptr64,void * __ptr64 * __ptr64,int,unsigned int * __ptr64,struct icon_size_t * __ptr64)
-    1.58: napi_get_cb_info<void,std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>,icon_size_t> icon-object.obj                          enum napi_status __cdecl napi_get_cb_info<void,class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> >,struct icon_size_t>(struct napi_env__ * __ptr64,struct napi_callback_info__ * __ptr64,void * __ptr64,void * __ptr64 * __ptr64,int,class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class...
-    1.51: napi_get_cb_info<void,napi_buffer_info>                                          reg-icon-stream.obj                      enum napi_status __cdecl napi_get_cb_info<void,struct napi_buffer_info>(struct napi_env__ * __ptr64,struct napi_callback_info__ * __ptr64,void * __ptr64,void * __ptr64 * __ptr64,int,struct napi_buffer_info * __ptr64)
+    1.59: __acrt_locale_initialize_ctype                                                   initctype.obj                            __acrt_locale_initialize_ctype
+    1.51: napi_get_cb_info<MenuObject*,int,int>                                            menu-object.obj                          napi_get_cb_info<MenuObject*,int,int>
+    1.51: napi_get_cb_info<MenuObject*,int,menu_item>                                      menu-object.obj                          napi_get_cb_info<MenuObject*,int,menu_item>
+    1.50: napi_get_cb_info<NotifyIconObject*,notify_icon_object_options>                   notify-icon-object.obj                   napi_get_cb_info<NotifyIconObject*,notify_icon_object_options>
+<...>

 Object files by code size (kilobytes, min 2.00):
-   19.70: SchedulerBase.obj
-   18.92: ResourceManager.obj
-   16.66: menu-object.obj
-   10.71: icon-object.obj
-    9.83: notify-icon-object.obj
-    8.55: data.obj
-    7.52: ScheduleGroupBase.obj
-    7.44: SearchAlgorithms.obj
-    7.12: InternalContextBase.obj
-    5.83: ContextBase.obj
-    5.78: SchedulerProxy.obj
-    5.53: TaskCollection.obj
-    5.21: event.obj
-    5.21: frame.obj
-    4.13: notify-icon-message-loop.obj
-    3.99: VirtualProcessor.obj
-    3.28: excptptr.obj
-    3.16: core.obj
-    3.05: write.obj
-    2.88: rtlocks.obj
-    2.61: mbctype.obj
-    2.42: argv_wildcards.obj
-    2.31: SchedulingNode.obj
-    2.06: per_thread_data.obj
+   95.26: output.obj
+   28.33: undname.obj
+   26.39: * Linker *
+   25.89: SchedulerBase.obj
+   22.12: ResourceManager.obj
+   20.69: menu-object.obj
+   13.50: cfout.obj
+   13.17: TaskCollection.obj
+   13.16: frame.obj
+   12.33: ContextBase.obj
+   12.25: notify-icon-object.obj
+   11.61: icon-object.obj
+    9.99: ScheduleGroupBase.obj
+    9.06: data.obj
+    8.91: wsetlocale.obj
+    8.10: SearchAlgorithms.obj
+    7.81: InternalContextBase.obj
+    7.34: argv_wildcards.obj
+    7.25: atox.obj
+    6.85: winapi_thunks.obj
+    6.22: SchedulerProxy.obj
+    6.20: event.obj
+    6.19: rtlocks.obj
+    5.22: VirtualProcessor.obj
+    4.75: UMSFreeVirtualProcessorRoot.obj
+    4.69: ThreadProxyFactoryManager.obj
+    4.67: notify-icon-message-loop.obj
+<...>
 
-Overall code:    243.09 kb
-Overall data:     12.31 kb
-Overall BSS:       4.21 kb
-Overall other:     1.45 kb
+Overall code:    613.41 kb
+Overall data:     12.43 kb
+Overall BSS:       4.22 kb
+Overall other:     1.43 kb

There's a whole new bunch of VC++ de-mangling and formatting code included... huh?

I couldn't see anything on the v12.0.0 changelog that made it look like this was a deliberate change, and 600kB+/200%+ extra for each addon is pretty heavy, so I thought it was worth raising, if only to have something for people to be pointed at.

For now, I'm happy to target an earlier node version.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    addonsIssues and PRs related to native addons.buildIssues and PRs related to build files or the CI.windowsIssues and PRs related to the Windows platform.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions