이번에는 tinyscheme 을 윈도에서 빌드하려고 하니 좀 성가시네. msvc 버전문제 인가?
그래서 간단하게 CMakeLists.txt 를 만들어봤다. 물론! 빌드되는것까지만 확인해본 것이니
좀더 둘러보고 써야겠지만. 어쨌거나 적어둔다.
펼쳐두기..
2010/01/22 추가. msvc9 에서 빌드해본거. 이전에 적은거랑 별 차이는 없다.펼쳐두기..
헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤
펼쳐두기..
# 플래폼설정. 이거 외에도 코드에서 snprintf 를 _snprintf 로 access 를
# _access 로 식의 약간의 변경이 필요. 아 짱나.
add_definitions(-DWIN32)
# 요 워닝은 일단 무시
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4996")
# 이건 feature 설정들
add_definitions(-DUSE_DL=0 -DUSE_MATH=0 -DUSE_ASCII_NAMES=0)
# DLL 뽑아내고
add_library(tinyscheme SHARED scheme.c)
# 스탠드얼론도 뽑아내고
add_executable(tinyscheme scheme.c)
2010/01/22 추가. msvc9 에서 빌드해본거. 이전에 적은거랑 별 차이는 없다.펼쳐두기..
scheme.c 에 다음 추가.
#ifdef _MSC_VER
# include <io.h>
# define access _access
# define snprintf _snprintf
#endif
CMakeLists.txt 에 아래 추가
project(tinyscheme)
add_executable(scheme scheme.c dynload.c)
add_library(scheme scheme.c dynload.c)
configure_file(init.scm ${tinyscheme_BINARY_DIR} COPY_ONLY)
워닝제거를 위해선 아래도 추가( 내가 원해 misc.cmake 에 들고다니는 코드에서 발췌 )
macro(suppress_msvc_warnings ns)
if(MSVC)
foreach(n ${ns})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd${n}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd${n}")
endforeach(n ${ns})
endif(MSVC)
endmacro(suppress_msvc_warnings ns)
suppress_msvc_warnings(4996)
//
// 아래 소스 빌드할때 써먹은 CMakeLists.txt
// 별거없고 USE_INTERFACE 를 디파인했다는것만 기억해두자
// 그외 여러가지 조정할게 많아 보이는데 아직 모름.
//
// PROJECT(play-with-tinyscheme)
// INCLUDE_DIRECTORIES(/home/yoonkn/tmp/tinyscheme1.39)
// LINK_DIRECTORIES(/home/yoonkn/tmp/tinyscheme1.39)
// LINK_LIBRARIES(tinyscheme)
// ADD_DEFINITIONS(-DUSE_INTERFACE)
//
// ADD_EXECUTABLE(a a.cpp)
extern "C" {
#include "scheme-private.h"
#include "scheme.h"
}
#include <unistd.h>
#include <iostream>
using namespace std;
static void die(const char* msg) {puts(msg); exit(-1);}
static pointer c_add(scheme* sc, pointer args);
int main()
{
// 초기화. 전역이 아니라 멀티쓰레드간에 써도 안심?
scheme* sc = scheme_init_new();
if(!sc) die("init failed");
// display 등으로 출력되는 값이 튀어나오는 곳이겠군.
scheme_set_output_port_file(sc, stdout);
// scheme 코드를 실행하려면 load_string 이나 load_file 을 쓰자
// scheme.c 를 보니 init.scm 등을 먼저 읽고 시작하는게 바른
// 사용방법인듯 하다. load_string 류 함수는 코드 실행후 실행여부를
// retcode 에, 평가된 값을 value 에 담아주는 모냥이다.
sc->vptr->load_string(sc, "(define foo \"fuckshit\")");
if(sc->retcode != 0) die("exec failed");
// scheme 내의 값을 읽으려면 요렇게. 심벌만 넣어서 실행하고
// .value 를 읽어오면 되는듯
sc->vptr->load_string(sc, "foo");
const char* foo_value = sc->vptr->string_value(sc->value);
puts(foo_value);
// C 쪽에서 만든 덧셈 함수를 scheme 인터프리터에 추가하자.
sc->vptr->scheme_define(sc,
sc->global_env,
sc->vptr->mk_symbol(sc, "c-add"),
sc->vptr->mk_foreign_func(sc, c_add));
// c_add 함 불러보고 리턴값을 찍어보자
sc->vptr->load_string(sc, "(c-add 111 222)");
if(sc->retcode != 0) die("fucked");
printf("(c-add ..) return : %d\n", sc->vptr->ivalue(sc->value));
// 이번엔 반대로 scheme 쪽에서 함수를 만들어보자
sc->vptr->load_string(sc, "(define (scm-add a b) (+ a b))");
if(sc->retcode != 0) die("fucked");
// 이걸 C 쪽에서 부르자.. 음 물론 scheme 코드 만들어서 load_string
// 써도 되겠지만.. C 레벨에서.. 어라? 인터페이스가 안빠져있네
// scheme_call 이란 함수가 있긴 한데 외부로 노출된 함수는 아니네
// 음.. 뭐 일단 내가 원했던 내용까지는 파악이 됐으니 걍 여기까지
// 정리. 그런데 scheme_init_new 는 안쪽에서 sc 를 malloc 해서
// 주는데 deinit 함수중에는 sc 자체를 free 까지 해주는 함수가
// 안보이네 일단 샘플이니 여기서 그냥 free 를 했지만 정말 써먹을
// 상황이 온다면 dll 간에 malloc/free 가 섞일수도 주의하자.
scheme_deinit(sc);
free(sc);
}
// scheme 에 노출할 함수는 pointer foo(scheme*, pointer) 형태의
// 시그너쳐를 가지고 pointer 를 통해서 인자들이 리스트 형태로
// 들어온다. 복잡한데 쓸거 아니니 이정도만 알면 안심
pointer c_add(scheme* sc, pointer args)
{
// 첫번째 인자가 존재하고 정수가 맞는지 확인
if(args == sc->NIL) return sc->NIL;
pointer a = pair_car(args);
if(!is_integer(a)) return sc->NIL;
// 이거.. 변수 따로 잡기 귀찮아서 그냥 덮어썼는데
// 그래서 arg list 들의 첫번째 car 를 팝 한 효과가 났다.
args = pair_cdr(args);
// 다음 인자가 존재하고 정수가 맞는지 확인 꼴을 보니 좀 머리 쓰면
// 이쁘게 짤수 있을거 같은데 오늘은 샘플이니 그냥..
if(args == sc->NIL) return sc->NIL;
pointer b = pair_car(args);
if(!is_integer(b)) return sc->NIL;
// 더한값을 scheme 자료형태로 리턴
return mk_integer(sc, ivalue(a) + ivalue(b));
}