bonescript는 beaglebone에 연결된 serial, i2c, gpio등을 javascript로 제어할 수 있는 npm 툴이다. serial, i2c, gpio는 system에 매우 밀접한 기능이라서 node-gyp로 되어 있다. gyp는 generate your project의 약자로 각 플랫폼에 맞게 프로젝트를 빌드하는 기능이다. 즉, beaglebone에 맞도록 컴파일해서 기능을 제공하는 것이다. 좀 더 이해를 돕기 위해 Rhio님의 블로그를 참고하면 좋겠다. bonescript는 beaglebone이 embedded linux이기 때문에 beaglebone에서 아무런 문제없이 node-gyp가 동작하고 또한 설치된다. 하지만 osx에 bonescript를 설치하면 설치 중간에 바로 에러가 난다. 바로 이 node-gyp내에 컴파일에서 에러가 나기 때문이다. 다음은 osx에 설치하면서 부딯친 문제들을 정리해 두었다. 굳이 embedded linux용 npm을 osx에 설치하려는 이유는 주 개발 PC가 osx였고, 매번 node.js 어플리케이션을 BBB에 deploy하기가 부담되기 때문에 osx에 bonescript를 설치하고, 실제 hardware i/o가 일어나지 않더라도 mock하도록 처리하고 싶었다.
1. node-gyp 설치
node-gyp를 설치한다.
$ npm install node-gyp
참고로 설치 후 node-gyp가 잘 동작되지 않을때는 다음의 폴더를 삭제 후 재설치하니 잘 동작되었다.
$ rm -rf ~/.node-gyp
2. misc.cpp파일 수정하기
node-gyp가 잘 설치되면, bonescript의 gyp가 misc.cpp를 빌드하려 한다. misc.cpp가 build대상파일이 되는 이유는 binding.gyp에 misc.cpp가 gyp파일이라고 명기되어 있기 때문이다.
{
"targets": [
{
"target_name": "misc",
"sources": [ "misc.cpp" ]
}
]
}
misc.cpp가 잘 컴파일된다면 gpio제어용으로 사용되는 gpioint.js의 instance로 연결되어 사용된다. 즉, BBB의 gpio를 제어하기 위해 misc.cpp가 컴파일되어야 한다. osx는 당연히 gpio를 사용하도록 허가되어 있지 않으므로 사용할 수 없어서 제거할 수 있겠지만 workaround로 misc.cpp를 수정할 수도 있겠다 싶어 살펴보았다.
misc.cpp는 <sys/epoll.h> 헤더파일에 대한 dependency가 존재한다. 코드 안에도 epoll_create() 등 많이 사용된다. epoll library는 I/O 이벤트 알림 기능이다. 즉, 불규칙적으로 GPIO로 데이터가 들어오면 system으로부터 event를 받는 구조로 되어 있다. 유사한 기능으로 select, kqueue 등이 있다. 특히 kqueue는 FreeBSD계열에서 사용되는 library로 osx는 epoll 대신 kqueue를 사용한다.
$ sudo npm install ../../../../bonescript/node_modules/bonescript
> bonescript@0.2.3 preinstall /Users/........................./node_modules/bonescript
> node-gyp clean || (exit 0); node-gyp configure build
CXX(target) Release/obj.target/misc/misc.o
../misc.cpp:1:9: warning: 'BUILDING_NODE_EXTENSION' macro redefined
#define BUILDING_NODE_EXTENSION
^
<command line>:4:9: note: previous definition is here
#define BUILDING_NODE_EXTENSION 1
^
../misc.cpp:8:10: fatal error: 'sys/epoll.h' file not found
#include <sys/epoll.h>
^
1 warning and 1 error generated.
make: *** [Release/obj.target/misc/misc.o] Error 1
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:267:23)
gyp ERR! stack at ChildProcess.EventEmitter.emit (events.js:98:17)
gyp ERR! stack at Process.ChildProcess._handle.onexit (child_process.js:789:12)
gyp ERR! System Darwin 12.4.0
gyp ERR! command "node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "configure" "build"
gyp ERR! cwd /Users/............................../node_modules/bonescript
gyp ERR! node -v v0.10.15
gyp ERR! node-gyp -v v0.10.6
gyp ERR! not ok
npm ERR! weird error 1
npm ERR! not ok code 0
생각이 여기까지 미치자 epoll to kqueue 컨버터를 찾아야 겠다고 판단했다. pnotify라는 프로젝트이다. 주 기능은 file system의 event notification을 제공하는 기능이나, 나처럼 epoll to kqueue컨버터가 필요했던 모양이다. epoll.h와 epoll.c파일을 misc.cpp가 있는 폴더에 추가하고, binding.gyp에 epoll.c를 추가하였다. 컴파일 결과 다음과 같이 추가 에러가 발생하였다.
$ sudo npm install ../../../../bonescript/node_modules/bonescript
> bonescript@0.2.3 preinstall /Users/....................../node_modules/bonescript
> node-gyp clean || (exit 0); node-gyp configure build
CXX(target) Release/obj.target/misc/misc.o
../misc.cpp:1:9: warning: 'BUILDING_NODE_EXTENSION' macro redefined
#define BUILDING_NODE_EXTENSION
^
<command line>:4:9: note: previous definition is here
#define BUILDING_NODE_EXTENSION 1
^
../misc.cpp:15:17: warning: using directive refers to implicitly-defined
namespace 'std'
using namespace std;
^
../misc.cpp:21:27: error: unknown type name 'EV_P_'
static void pollpri_event(EV_P_ ev_io * req, int revents);
^
../misc.cpp:21:39: error: expected ')'
static void pollpri_event(EV_P_ ev_io * req, int revents);
^
../misc.cpp:21:26: note: to match this '('
static void pollpri_event(EV_P_ ev_io * req, int revents);
^
../misc.cpp:32:5: error: unknown type name 'ev_io'
ev_io event_watcher, *ew;
^
../misc.cpp:148:31: error: unknown type name 'EV_P_'
static void pollpri_event(EV_P_ ev_io * req, int revents) {
^
../misc.cpp:148:43: error: expected ')'
static void pollpri_event(EV_P_ ev_io * req, int revents) {
^
../misc.cpp:148:30: note: to match this '('
static void pollpri_event(EV_P_ ev_io * req, int revents) {
^
../misc.cpp:38:16: warning: expression result unused [-Wunused-value]
PRINTF("EV_DEFAULT_ = %s\n", TEST_EV_DEFAULT_NAME);
^~~~~~~~~~~~~~~~~~~~
../misc.cpp:37:16: warning: expression result unused [-Wunused-value]
PRINTF("Entering Init\n");
^~~~~~~~~~~~~~~~~
../misc.cpp:38:38: warning: expression result unused [-Wunused-value]
PRINTF("EV_DEFAULT_ = %s\n", TEST_EV_DEFAULT_NAME);
^~~~~~~~~~~~~~~~~~~~
../misc.cpp:25:30: note: expanded from macro 'TEST_EV_DEFAULT_NAME'
#define TEST_EV_DEFAULT_NAME STR(EV_DEFAULT_)
^~~~~~~~~~~~~~~~
../misc.cpp:24:20: note: expanded from macro 'STR'
#define STR(macro) QUOTE(macro)
^~~~~~~~~~~~
../misc.cpp:23:26: note: expanded from macro 'QUOTE'
#define QUOTE(name, ...) #name
^~~~~
<scratch space>:112:1: note: expanded from macro '#'
"EV_DEFAULT_"
^~~~~~~~~~~~~
../misc.cpp:47:16: warning: expression result unused [-Wunused-value]
PRINTF("Leaving Init\n");
^~~~~~~~~~~~~~~~
../misc.cpp:51:16: warning: expression result unused [-Wunused-value]
PRINTF("Entering Pollpri constructor\n");
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../misc.cpp:63:20: error: use of undeclared identifier 'EV_DEFAULT_'; did you
mean 'UV_EFAULT'?
ev_io_stop(EV_DEFAULT_ &event_watcher);
^~~~~~~~~~~
UV_EFAULT
/Users/..../.node-gyp/0.10.15/deps/uv/include/uv.h:137:16: note: 'UV_EFAULT'
declared here
UV_ERRNO_MAP(UV_ERRNO_GEN)
^
/Users/..../.node-gyp/0.10.15/deps/uv/include/uv.h:90:3: note: expanded from
macro 'UV_ERRNO_MAP'
XX( 15, EFAULT, "bad address in system call argument") \
^
/Users/..../.node-gyp/0.10.15/deps/uv/include/uv.h:135:36: note: expanded from
macro 'UV_ERRNO_GEN'
#define UV_ERRNO_GEN(val, name, s) UV_##name = val,
^
<scratch space>:141:1: note: expanded from macro 'UV_'
UV_EFAULT
^
../misc.cpp:60:16: warning: expression result unused [-Wunused-value]
PRINTF("Entering Pollpri destructor\n");
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../misc.cpp:84:16: warning: expression result unused [-Wunused-value]
PRINTF("open(%s) returned %d: %s\n", p->path, fd, strerror(errno));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
../misc.cpp:84:49: warning: expression result unused [-Wunused-value]
PRINTF("open(%s) returned %d: %s\n", p->path, fd, strerror(errno));
~ ^~~~
../misc.cpp:84:55: warning: expression result unused [-Wunused-value]
PRINTF("open(%s) returned %d: %s\n", p->path, fd, strerror(errno));
^~
../misc.cpp:88:16: warning: expression result unused [-Wunused-value]
PRINTF("epoll_create(1) returned %d: %s\n", epfd, strerror(errno));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../misc.cpp:88:53: warning: expression result unused [-Wunused-value]
PRINTF("epoll_create(1) returned %d: %s\n", epfd, strerror(errno));
^~~~
../misc.cpp:90:21: error: use of undeclared identifier 'EPOLLPRI'; did you mean
'EPOLLERR'?
ev.events = EPOLLPRI;
^~~~~~~~
EPOLLERR
../epoll.h:33:5: note: 'EPOLLERR' declared here
EPOLLERR = 0x008,
^
../misc.cpp:93:16: warning: expression result unused [-Wunused-value]
PRINTF("epoll_ctl(%d) returned %d (%d): %s\n", fd, n, epfd,...
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../misc.cpp:93:56: warning: expression result unused [-Wunused-value]
...returned %d (%d): %s\n", fd, n, epfd, strerror(errno));
^~
../misc.cpp:93:60: warning: expression result unused [-Wunused-value]
...returned %d (%d): %s\n", fd, n, epfd, strerror(errno));
^
../misc.cpp:93:63: warning: expression result unused [-Wunused-value]
...returned %d (%d): %s\n", fd, n, epfd, strerror(errno));
^~~~
../misc.cpp:99:16: warning: expression result unused [-Wunused-value]
PRINTF("seek(%d) %d bytes: %s\n", fd, m, strerror(errno));
^~~~~~~~~~~~~~~~~~~~~~~~~
../misc.cpp:99:43: warning: expression result unused [-Wunused-value]
PRINTF("seek(%d) %d bytes: %s\n", fd, m, strerror(errno));
^~
../misc.cpp:99:47: warning: expression result unused [-Wunused-value]
PRINTF("seek(%d) %d bytes: %s\n", fd, m, strerror(errno));
^
../misc.cpp:102:16: warning: expression result unused [-Wunused-value]
PRINTF("read(%d) %d bytes (%s): %s\n", fd, m, buf, strerror(errno));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../misc.cpp:102:48: warning: expression result unused [-Wunused-value]
PRINTF("read(%d) %d bytes (%s): %s\n", fd, m, buf, strerror(errno));
^~
../misc.cpp:102:52: warning: expression result unused [-Wunused-value]
PRINTF("read(%d) %d bytes (%s): %s\n", fd, m, buf, strerror(errno));
^
../misc.cpp:102:55: warning: expression result unused [-Wunused-value]
PRINTF("read(%d) %d bytes (%s): %s\n", fd, m, buf, strerror(errno));
^~~
../misc.cpp:106:21: error: use of undeclared identifier 'EV_DEFAULT_'; did you
mean 'UV_EFAULT'?
ev_io_start(EV_DEFAULT_ p->ew);
^~~~~~~~~~~
UV_EFAULT
/Users/..../.node-gyp/0.10.15/deps/uv/include/uv.h:137:16: note: 'UV_EFAULT'
declared here
UV_ERRNO_MAP(UV_ERRNO_GEN)
^
/Users/..../.node-gyp/0.10.15/deps/uv/include/uv.h:90:3: note: expanded from
macro 'UV_ERRNO_MAP'
XX( 15, EFAULT, "bad address in system call argument") \
^
/Users/..../.node-gyp/0.10.15/deps/uv/include/uv.h:135:36: note: expanded from
macro 'UV_ERRNO_GEN'
#define UV_ERRNO_GEN(val, name, s) UV_##name = val,
^
<scratch space>:141:1: note: expanded from macro 'UV_'
UV_EFAULT
^
../misc.cpp:106:33: error: expected ')'
ev_io_start(EV_DEFAULT_ p->ew);
^
../misc.cpp:106:20: note: to match this '('
ev_io_start(EV_DEFAULT_ p->ew);
^
../misc.cpp:67:16: warning: expression result unused [-Wunused-value]
PRINTF("Entered New\n");
^~~~~~~~~~~~~~~
../misc.cpp:111:16: warning: expression result unused [-Wunused-value]
PRINTF("Leaving New\n");
^~~~~~~~~~~~~~~
../misc.cpp:117:16: warning: expression result unused [-Wunused-value]
PRINTF("fd = %d, epfd = %d, revents = 0x%0x\n", fd, epfd, revents);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../misc.cpp:117:57: warning: expression result unused [-Wunused-value]
PRINTF("fd = %d, epfd = %d, revents = 0x%0x\n", fd, epfd, revents);
^~
../misc.cpp:117:61: warning: expression result unused [-Wunused-value]
PRINTF("fd = %d, epfd = %d, revents = 0x%0x\n", fd, epfd, revents);
^~~~
../misc.cpp:118:23: error: use of undeclared identifier 'EV_READ'
if(revents != EV_READ) {
^
../misc.cpp:126:16: warning: expression result unused [-Wunused-value]
PRINTF("seek(%d) %d bytes: %s\n", fd, m, strerror(errno));
^~~~~~~~~~~~~~~~~~~~~~~~~
../misc.cpp:126:43: warning: expression result unused [-Wunused-value]
PRINTF("seek(%d) %d bytes: %s\n", fd, m, strerror(errno));
^~
../misc.cpp:126:47: warning: expression result unused [-Wunused-value]
PRINTF("seek(%d) %d bytes: %s\n", fd, m, strerror(errno));
^
../misc.cpp:129:16: warning: expression result unused [-Wunused-value]
PRINTF("read(%d) %d bytes (%s): %s\n", fd, m, buf, strerror(errno));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../misc.cpp:129:48: warning: expression result unused [-Wunused-value]
PRINTF("read(%d) %d bytes (%s): %s\n", fd, m, buf, strerror(errno));
^~
../misc.cpp:129:52: warning: expression result unused [-Wunused-value]
PRINTF("read(%d) %d bytes (%s): %s\n", fd, m, buf, strerror(errno));
^
../misc.cpp:129:55: warning: expression result unused [-Wunused-value]
PRINTF("read(%d) %d bytes (%s): %s\n", fd, m, buf, strerror(errno));
^~~
../misc.cpp:117:67: warning: expression result unused [-Wunused-value]
PRINTF("fd = %d, epfd = %d, revents = 0x%0x\n", fd, epfd, revents);
^~~~~~~
../misc.cpp:150:44: error: use of undeclared identifier 'req'
Pollpri *p = static_cast<Pollpri*>(req->data);
^
../misc.cpp:151:21: error: use of undeclared identifier 'revents'; did you mean
'kevent'?
p->Event(p, revents);
^~~~~~~
kevent
/usr/include/sys/event.h:308:9: note: 'kevent' declared here
int kevent(int kq, const struct kevent *changelist, int nchanges,
^
../misc.cpp:151:21: error: cannot initialize a parameter of type 'int' with an
lvalue of type 'int (int, const struct kevent *, int, struct kevent *,
int, const struct timespec *)'
p->Event(p, revents);
^~~~~~~
../misc.cpp:115:33: note: passing argument to parameter 'revents' here
void Event(Pollpri * p, int revents) {
^
../misc.cpp:149:16: warning: expression result unused [-Wunused-value]
PRINTF("Entered pollpri_event\n");
^~~~~~~~~~~~~~~~~~~~~~~~~
../misc.cpp:152:16: warning: expression result unused [-Wunused-value]
PRINTF("Leaving pollpri_event\n");
^~~~~~~~~~~~~~~~~~~~~~~~~
../misc.cpp:160:16: warning: expression result unused [-Wunused-value]
PRINTF("Calling Init\n");
^~~~~~~~~~~~~~~~
40 warnings and 13 errors generated.
make: *** [Release/obj.target/misc/misc.o] Error 1
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:267:23)
gyp ERR! stack at ChildProcess.EventEmitter.emit (events.js:98:17)
gyp ERR! stack at Process.ChildProcess._handle.onexit (child_process.js:789:12)
gyp ERR! System Darwin 12.4.0
gyp ERR! command "node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "configure" "build"
gyp ERR! cwd /User/............................/node_modules/bonescript
gyp ERR! node -v v0.10.15
gyp ERR! node-gyp -v v0.10.6
gyp ERR! not ok
npm ERR! weird error 1
npm ERR! not ok code 0
여기까지 팠다. 더 파서 kqueue를 동작시키게 하면 좋겠지만, 시간이 부족하여, binding,gyp, misc.cpp 파일을 모두 제거하고 osx에 bonescript를 인스톨하였다. 다음에 시간이 허락되면 이 부분부터 다시 digging해야 겠다.
Recent Comments