2016-09-23 2 views
0

Я работаю над приложением, которое использует пакет tcl, реализованный на C++ и связанный как статическая библиотека (приложение давно разработано). Это следующее:пакет требуется со статическим lib

// Library code 
extern "C" int testlib_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)) 
{ 
    return Tcl_PkgProvide(interp, "testlib", "1.6"); 
} 

extern "C" int testlib_Init _ANSI_ARGS_((Tcl_Interp *interp)) 
{ 
    return testlib_SafeInit(interp); 
} 


// Application code 
extern "C" int testlib_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)); 
extern "C" int testlib_Init _ANSI_ARGS_((Tcl_Interp *interp)); 

int main() 
{ 
    Tcl_Interp* interp = Tcl_CreateInterp(); 
    Tcl_Init(interp); 
    Tcl_PkgProvide(interp, "testlib", "1.6"); 
    Tcl_StaticPackage(interp, "testlib", testlib_Init, testlib_SafeInit); 
    Tcl_Eval(interp, "package require testlib"); 
    std::cout << "Res = " << Tcl_GetStringResult(interp); 
    return 0; 
} 

Когда я удаление строки Tcl_PkgProvide (интерп, "testlib", "1,6"); из основного, пакет становится невидимым. Также я заметил, что testlib_Init и testlib_SafeInit не вызываются. Я ожидаю, что они должны быть вызваны из пакета, требующего testlib. Как я понимаю из документов, каждый пакет должен иметь pkgIndex.tcl в auto_path или tcl_pkgPath, который должен содержать строку (пакет ifneeded testlib 1.6 {load {} testlib}), но здесь обе переменные не содержат такой файл индекса.

Это правильный способ предоставления пакетов? Есть ли документация, связанная с предоставлением пакетов с использованием статических библиотек?

ответ

1

Ну, самый простой способ статического предоставления пакета - просто установить его напрямую. Код инициализации пакета должен быть одним вызовом Tcl_PkgProvide - вы не делаете этого из main() обычно - и вам, вероятно, вообще не нужно Tcl_StaticPackage, если вы не хотите устанавливать код в подшивки.

int main(int argc, char*argv[]) 
{ 
    Tcl_FindExecutable(argv[0]); 

    Tcl_Interp* interp = Tcl_CreateInterp(); 
    Tcl_Init(interp); 
    testlib_Init(interp); 
    // OK, setup is now done 

    Tcl_Eval(interp, "package require testlib"); 
    std::cout << "Res = " << Tcl_GetStringResult(interp) << "\n"; 
    return 0; 
} 

Однако мы можем шаг к использованию Tcl_StaticPackage. Это позволяет коду сказать «вместо того, чтобы загружать DLL с таким именем, я уже знаю, что код: вот его точки входа». Если вы это делаете, вам нужно , а также установить сценарий package ifneeded; они выполняются только с помощью API сценариев.

int main(int argc, char*argv[]) 
{ 
    Tcl_FindExecutable(argv[0]); 

    Tcl_Interp* interp = Tcl_CreateInterp(); 
    Tcl_Init(interp); 
    Tcl_StaticPackage(interp, "testlib", testlib_Init, testlib_SafeInit); 
    Tcl_Eval(interp, "package ifneeded testlib 1.6 {load {} testlib}"); 
    // OK, setup is now done 

    Tcl_Eval(interp, "package require testlib"); 
    std::cout << "Res = " << Tcl_GetStringResult(interp) << "\n"; 
    return 0; 
} 

testlib в load вызова должен соответствовать testlib в Tcl_StaticPackage вызова. testlib в package require, package ifneeded и Tcl_PkgProvide также должны соответствовать всем (как и в случае 1.6, номер версии).


Другие незначительные проблемы

Кроме того, вам не нужно использовать _ANSI_ARGS_ оболочку макроса. Это совершенно устарело, для действительно древних и дерьмовых компиляторов, которых мы больше не поддерживаем. Просто замените _ANSI_ARGS_((Tcl_Interp *interp)) на (Tcl_Interp *interp). И не забудьте сначала позвонить Tcl_FindExecutable, чтобы инициализировать статические части библиотеки Tcl. Если у вас нет argv[0], доступных для передачи в него, используйте вместо этого NULL; это влияет на несколько более неясных систем интроспекции на некоторых платформах, но вы, вероятно, не заботитесь о них. Однако, инициализация библиотеки в целом очень полезно: например, она позволяет вам правильно понимать схему кодирования имени файловой системы! Это может быть немного важно для кодирования ...

Смежные вопросы