NodeJS and FreeBSD – Part 1

by David Carlier
Nodejs is well known to allow building server applications in full javascript. In this article, we’ll see how to build nodejs from source code on FreeBSD. You will need autoconf tools, GNU make, Python, linprocfs enabled and libexecinfo installed. GCC/G++ compiler suite (C++11 compliant, ideally 4.8 series or above) or possibly clang can be used to compile the whole source.


 
To start, we need the nodejs source code from this url http://www.nodejs.org/dist/latest where we can find this archive (during the article writing, the last version known is 0.12.2), node-v<version>.tar.gz.
Be prepared to be patient, you have enough time for a cup of coffee, the compilation time needed can be quite long…
Once downloaded and extracted, the famous command trio needs to be typed:
• ./configure –dest-os=freebsd
• gmake
• gmake install
It’s pretty straightforward on first glance. On FreeBSD, when v8 is compiled we get some compilation errors:

clang++ ‘-DV8_TARGET_ARCH_X64’ ‘-DENABLE_DISASSEMBLER’
‘-DENABLE_HANDLE_ZAPPING’ -I../deps/v8 -pthread
-Wall -Wextra -Wno-unused-parameter -m64 -fno-strictaliasing
-I/usr/local/include -O3 -ffunction-sections
-fdata-sections -fno-omit-frame-pointer -fdata-sections
-ffunction-sections -O3 -fno-rtti -fno-exceptions -MMD
-MF /root/node-v0.12.2/out/Release/.deps//root/nodev0.12.2/
out/Release/obj.target/v8_libbase/deps/v8/src/
base/platform/platform-freebsd.o.d.raw -c -o /root/
node-v0.12.2/out/Release/obj.target/v8_libbase/deps/v8/
src/base/platform/platform-freebsd.o ../deps/v8/src/
base/platform/platform-freebsd.cc
../deps/v8/src/base/platform/platform-freebsd.cc:159:11:
error: member reference base type ‘int’ is not a
structure or union
result.push_back(SharedLibraryAddress(start_of_path,
start, end));
~~~~~~^~~~~~~~~~
../deps/v8/src/base/platform/platform-freebsd.cc:191:53:
error: use of undeclared identifier ‘MAP_NORESERVE’
MAP_PRIVATE | MAP_ANON | MAP_
NORESERVE,
^
../deps/v8/src/base/platform/platform-freebsd.cc:263:48:
error: use of undeclared identifier ‘MAP_NORESERVE’
MAP_PRIVATE | MAP_ANON | MAP_
NORESERVE,
^
../deps/v8/src/base/platform/platform-freebsd.cc:291:40:
error: use of undeclared identifier ‘MAP_NORESERVE’
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE |
MAP_FIXED,

4 errors generated.
Ok, so a result variable ought to be a std::vector but it’s considered wrongly as an int and furthermore a wrong mmap flag is used. Let’s fix it!

std::vector<SharedLibraryAddress> result;
static const int MAP_LENGTH = 1024;
int fd = open(“/proc/self/maps”, O_RDONLY);
if (fd < 0) return result;
while (true) {
char addr_buffer[11];
addr_buffer[0] = ‘0’;
addr_buffer[1] = ‘x’;
addr_buffer[10] = 0;
int result = read(fd, addr_buffer + 2, 8);
if (result < 8) break;
unsigned start = StringToLong(addr_buffer);
result = read(fd, addr_buffer + 2, 1);
if (result < 1) break;
if (addr_buffer[2] != ‘-’) break;
result = read(fd, addr_buffer + 2, 8);
if (result < 8) break;
unsigned end = StringToLong(addr_buffer);
char buffer[MAP_LENGTH];
int bytes_read = -1;
do {
bytes_read++;
if (bytes_read >= MAP_LENGTH - 1)
break;
result = read(fd, buffer + bytes_read, 1);

Apparently, there are two different variables with the same name. Let’s rename the second, the int type, to res for example so the vector result variable can legitimately call push _ back method. That fixes the first error.

std::vector<SharedLibraryAddress> result;
static const int MAP_LENGTH = 1024;
int fd = open(“/proc/self/maps”, O_RDONLY);
if (fd < 0) return result;
while (true) {
char addr_buffer[11];
addr_buffer[0] = ‘0’;
addr_buffer[1] = ‘x’;
addr_buffer[10] = 0;
int res= read(fd, addr_buffer + 2, 8);
if (res < 8) break;
unsigned start = StringToLong(addr_buffer);
res = read(fd, addr_buffer + 2, 1);
if (res < 1) break;
if (addr_buffer[2] != ‘-’) break;
res = read(fd, addr_buffer + 2, 8);
if (res < 8) break;
unsigned end = StringToLong(addr_buffer);
char buffer[MAP_LENGTH];
int bytes_read = -1;
do {
bytes_read++;
if (bytes_read >= MAP_LENGTH - 1)
break;
res = read(fd, buffer + bytes_read, 1);

Let’s have a look at the mmap problem.
MAP_NORESERVE is a specific flag which guarantees no swap space will be used for the mapping. However, it is a flag usable on Linux and Solaris /SunOS.

mmap(OS::GetRandomMmapAddr(),
size,
PROT_NONE,
MAP_PRIVATE | MAP_ANON | MAP_
NORESERVE,
kMmapFd,
kMmapFdOffset);
=>
mmap(OS::GetRandomMmapAddr(),
size,
PROT_NONE,
MAP_PRIVATE | MAP_ANON,
kMmapFd,
kMmapFdOffset);
void* reservation = mmap(OS::GetRandomMmapAddr(),
request_size,
PROT_NONE,
MAP_PRIVATE | MAP_ANON | MAP_
NORESERVE,
kMmapFd,
kMmapFdOffset);
=>
void* reservation = mmap(OS::GetRandomMmapAddr(),
request_size,
PROT_NONE,
MAP_PRIVATE | MAP_ANON,
kMmapFd,
kMmapFdOffset);

Once modified in every mmap call, we can now retry compiling. However, we get another compilation error. This time, it casts a pthread_self returns call to an int.
deps/v8/src/base/platform/platform-posix.cc:331:10: error:
static_cast from ‘pthread_t’ (aka ‘pthread *’) to ‘int’
is not allowed
return static_cast<int>(pthread_self());
The problem is, on FreeBSD, a pthread_t type is not an integral type at all but an opaque struct.
Instead, we might replace this line by:

return static_cast<int>(reinterpret_cast<inptr_t>(pthread_
self()));

Now we are finally able to compile. After a couple of minutes, it is finished but we have still one source to update: lib/dns.js. Add these two lines after line 127:

if (process.platform === ‘freebsd’ && family !== 6)
hints &= ~exports.V4MAPPED;

Because FreeBSD does not support this flag, it ought to be cleared. This is all for compilation and it is ready to be used. Next time, we’ll have an overlook in the application’s building part and ought to see the potential of this library.


 

ABOUT THE AUTHOR

David Carlier has been working as a software developer since 2001. He used FreeBSD for more than 10 years and starting from this year, he became involved with the HardenedBSD project and performed serious developments on FreeBSD. He worked for a mobile product company that provides C++ APIs for two years in Ireland. From this, he became completely inspired to develop on FreeBSD.

Join iX Newsletter

iXsystems values privacy for all visitors. Learn more about how we use cookies and how you can control them by reading our Privacy Policy.
π