Stop-gap measure to debug a Native Node Addon on Windows
Published: 2023-08-07 12:50:59

While working on building a [project](https://github.com/P2PFlix/libtorrent) that includes a `NodeJs` addon using `N-API` for `Windows` (and *nix), I found that binaries built on my machine work but the same binaries do not work on another machine. 


![loading libtorrent on my machine](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a948fj0kv2u9auya215g.png)



![loading libtorrent on another machine](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dkr0tf1j9atkoi0o5lq4.png)

But the file(s) are all present. What is happening? The same behaviour was observed on Linux and MacOS machines other than mine.

I would have switched to Linux and used `strace` to see what was happening, but I wanted to see if Windows has any good alternatives. After some quick Google searching, I realized that I could use the built-in `Visual Studio` debugger. 

> Note: I assume that you have the Visual Studio environment setup for C++ development on windows, along with the required SDKs installed



The commands I used to load and test the `libtorrent` build are (in a NodeJs shell) - 

```js
const lib = require('./libtorrent.node');
```

So I tried to find a Debug target (using the CMake extension that populates Visual Studio with stuff)

![Debug targets](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wie6wun681kgocachzhy.png)

No luck. Next, I opened Visual Studio and tried to start a `NodeJs` process using the debugger - 


![Visual Studio debug menu](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ta59erhyyukq6hmuobks.png)

But the "Start Debugging" option was greyed out. However, the "Attach to Process" option is available. Choosing that option opens the following menu - 



![Attach to process menu](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pxjyi2ikyy1z8kdl44fy.png)


The `Module` window will be of interest to us

![Visual Studio Module window](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/up52hz4nkkrpbukg2q8n.png)

Notice the timestamp column. Lets sort the list by timestamp and focus on the rows with a timestamp -

![Close-up of module window last few rows](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xbql6tfn45yok7tymnd1.png)

This makes sense as we haven't loaded the addon yet. Let's load the addon through `Node` and check the window again


![loading libtorrent](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t48rk2sncpf0rax7azpg.png)


We see a few more entries. On observing them, we see the following:
- libcrypto-3-x64.dll
- libssl-3-x64.dll

Going through the dependencies, we see that our project's main dependency [libtorrent](https://github.com/arvidn/libtorrent) depends on `OpenSSL`. Finally it clicked that I installed `OpenSSL` through `choco`

## Solution 1: Bundle and distribute required DLLs
Let's try to bundle the required DLLs with the project

![libtorrent with additional DLLs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9yftsoggbbik2bmsi9j0.png)

And we see that `libtorrent` is successfully loaded

![successfully loading libtorrent](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t1n9qudcldza7cwd764i.png)

But that's not a feasible solution. There might be scenarios where one cannot bundle multiple `DLLs` due to some restriction. How do we proceed?

## Solution 2: If it works, it ain't stupid

We know that the project depends on `libcrypto` and `libssl`, but probably uses a few functions or items from them. To test this theory out, I modified my project's `CMakeLists.txt` file to fetch `openssl` from `Github` using CMake's built in (version `3.11` and later) `FetchContent`

The following is an extract of the `CMakeLists.txt` file:

```cmake
include(FetchContent)
FetchContent_Declare(
    openssl
    GIT_REPOSITORY https://github.com/janbar/openssl-cmake.git
    SOURCE_DIR ${CMAKE_SOURCE_DIR}/lib/openssl
    GIT_TAG 392d455cd0b0fe992b312c9648eb5ea87e3afcea
)

FetchContent_MakeAvailable(openssl)
set(OPENSSL_ROOT_DIR ${CMAKE_SOURCE_DIR}/lib/openssl/*)

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    set(OPENSSL_CRYPTO_LIBRARY ${CMAKE_SOURCE_DIR}/build/_deps/openssl-build/crypto/Debug)
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
    set(OPENSSL_CRYPTO_LIBRARY ${CMAKE_SOURCE_DIR}/build/_deps/openssl-build/crypto/Release)
endif()
```
> The statement to set `OPENSSL_CRYPTO_LIBRARY` can be optimised further

This resulted in the following files being generated - 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nrap4tadj6a7jdju3fnv.png)

> the `openssl` binary is built as default behaviour that can be customized 


![libtorrent with statically linked openssl](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sjn3izluglfn4981wvfs.png)
> Shaky cam courtesy of a friend