괜히 궁금해져서 문서 뒤져봤네.
예제코드.
폰트지정하는 코드가 핵심.
#lang slideshow
(current-main-font "malgun")
(slide
#:title "안녕"
(t (number->string (current-font-size)))
(t "폰트 높낮이가 왜 다르냐")
(t "정말 눈에 거슬린다")
'next
(t "폰트를 지정해주니 해결됐엉"))
헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤헤
#lang slideshow
(current-main-font "malgun")
(slide
#:title "안녕"
(t (number->string (current-font-size)))
(t "폰트 높낮이가 왜 다르냐")
(t "정말 눈에 거슬린다")
'next
(t "폰트를 지정해주니 해결됐엉"))
cmake_minimum_required(VERSION 2.8)
if(WIN32)
# PLT 경로
set(PLTDIR "C:/Program Files/PLT" CACHE PATH "PLT scheme dir")
# -I, CFAGS, LDFLAGS 등 기본설정
include_directories("${PLTDIR}/include")
link_directories("${PLTDIR}/lib/msvc")
link_libraries(libmzsch3m_6ncc9s)
# 빌드후 테스팅을 편하게 하려고 dll 복사해줬다
configure_file("${PLTDIR}/lib/libmzsch3m_6ncc9s.dll" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY)
else()
# 지금은 윈도우 사용중이라.
endif()
# 필수
add_definitions(/DMZ_PRECISE_GC=1)
# base.i 가 소스리스트에 포함되어있고
add_executable(a a.cpp base.i)
# base.i 는 요 커맨드에 의해서 생성.
# PLT 문서는 .c 를 쓰는데 그럴경우 cmake 에서 좀 피곤하게 돌기때문에 .i 로 바꿨다.
add_custom_command(
OUTPUT base.i
COMMAND ${PLTDIR}/mzc --c-mods base.i ++lib scheme/base
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)
그리고 테스트로작성한 a.cpp 는 ( 위 문서의 코드를 그냥 베낀 정도의 코드 )
[code cpp]
#include "scheme.h"
#include "base.i" // mzc 가 생성한놈 원 문서는 .c 를 쓰지만 난 빌드편하게 하려다 보니 .i 썼다
static int run(Scheme_Env* e, int argc, char* argv[]);
int main(int argc, char* argv[])
{
// main 을 후킹해서 돌아가는 스타일
return scheme_main_setup(1, run, argc, argv);
}
// 아.. 드럽다. s7 이나 tiny_scheme 같은 경우는 대강 문서 보고 헤더
// 구경하면서 쓰는게 가능한데 이놈은 그렇질 못하다. 가비지콜렉션
// 때문인데... 흠. 문서를 좀더 읽기 전에 달려들었다간 낭패보기 쉽겠다.
static int run(Scheme_Env* e, int argc, char* argv[])
{
Scheme_Object* v;
MZ_GC_DECL_REG(2);
MZ_GC_VAR_IN_REG(0, e);
MZ_GC_VAR_IN_REG(1, v);
MZ_GC_REG();
declare_modules(e); // base.i 에서 나온거
v = scheme_intern_symbol("scheme/base");
scheme_namespace_require(v);
v = scheme_eval_string("(+ 1 2 3)", e);
if(SCHEME_INTP(v))
printf("result: %d\n", SCHEME_INT_VAL(v));
MZ_GC_UNREG();
return 0;
}
[/code]
참고로 이렇게 떨어진 a.exe 는 Release 빌드시 대략 556KB, 저 따라다녀야 하는 dll 은 2.5 MB
펼쳐두기..
# 플래폼설정. 이거 외에도 코드에서 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));
}