предлагаю вот такое вот улучшение в LinKernel:
Код:
PROCEDURE StrStartsWith (IN s, pfx: ARRAY OF CHAR): BOOLEAN;
VAR
pos: INTEGER;
BEGIN
pos := 0;
WHILE (s[pos] # 0X) & (pfx[pos] # 0X) & (s[pos] = pfx[pos]) DO INC(pos) END;
RETURN (pfx[pos] = 0X)
END StrStartsWith;
PROCEDURE StrStripDll (VAR s: ARRAY OF CHAR);
VAR
slen: INTEGER;
BEGIN
slen := LEN(s$);
IF (slen > 4) & (s[slen - 4] = '.') &
((s[slen - 3] = 'd') OR (s[slen - 3] = 'D')) &
((s[slen - 2] = 'l') OR (s[slen - 2] = 'L')) &
((s[slen - 1] = 'l') OR (s[slen - 1] = 'L'))
THEN
s[slen - 4] := 0X
END
END StrStripDll;
PROCEDURE StrHasSO (IN s: ARRAY OF CHAR): BOOLEAN;
VAR
pos, slen: INTEGER;
BEGIN
pos := 0; slen := LEN(s$);
WHILE pos + 2 < slen DO
WHILE (pos + 2 < slen) & ((s[pos] # '.') OR (s[pos + 1] # 's') OR (s[pos + 2] # 'o')) DO INC(pos) END;
IF (s[pos] = '.') & (s[pos + 1] = 's') & (s[pos + 2] = 'o') &
((s[pos + 3] = 0X) OR (s[pos + 3] = '.')) THEN
RETURN TRUE
END;
INC(pos, 3)
END;
RETURN FALSE
END StrHasSO;
PROCEDURE SStrPrepend (VAR s: ARRAY OF SHORTCHAR; IN pfx: ARRAY OF SHORTCHAR);
VAR
plen, slen, f: INTEGER;
BEGIN
plen := LEN(pfx$);
IF plen > 0 THEN
slen := LEN(s$);
WHILE slen >= 0 DO s[slen + plen] := s[slen]; DEC(slen) END;
FOR f := 0 TO plen - 1 DO s[f] := pfx[f] END
END
END SStrPrepend;
(* k8: try "lib<dll>.so" first *)
PROCEDURE TryDlOpen (IN dll: ARRAY OF CHAR): Dl.HANDLE;
VAR
soadded: BOOLEAN;
res: INTEGER;
h: Dl.HANDLE;
BEGIN
h := Dl.NULL;
IF (LEN(dll) > 0) & (dll[0] # 0X) THEN
(*log.String("***XXX***: dll=<"); log.String(dll); log.String(">"); log.Ln;*)
tmpsonamebufL := dll$;
StrStripDll(tmpsonamebufL);
(*log.String("000: dll=<"); log.String(tmpsonamebufL); log.String(">"); log.Ln;*)
(* append ".so" *)
soadded := ~StrHasSO(tmpsonamebufL);
IF soadded THEN tmpsonamebufL := tmpsonamebufL$ + ".so" END;
(*log.String("001: name=<"); log.String(tmpsonamebufL); log.String(">"); log.Ln;*)
(* try with "lib" prefix *)
IF ~StrStartsWith(tmpsonamebufL, "lib") THEN
Utf.StringToUtf8(tmpsonamebufL, tmpsonamebuf, res); ASSERT(res = 0);
SStrPrepend(tmpsonamebuf, "lib");
(*log.String("002: name=<"); log.String(LONG(tmpsonamebuf)); log.String(">"); log.Ln;*)
h := Dl.dlopen(tmpsonamebuf, Dl.RTLD_LAZY + Dl.RTLD_GLOBAL);
END;
(* try without "lib" prefix *)
IF h = Dl.NULL THEN
(*log.String("003: name=<"); log.String(tmpsonamebufL); log.String(">"); log.Ln;*)
Utf.StringToUtf8(tmpsonamebufL, tmpsonamebuf, res); ASSERT(res = 0);
h := Dl.dlopen(tmpsonamebuf, Dl.RTLD_LAZY + Dl.RTLD_GLOBAL);
END;
(* finally, try as is *)
IF (h = Dl.NULL) & soadded THEN
(*log.String("004: name=<"); log.String(dll); log.String(">"); log.Ln;*)
Utf.StringToUtf8(dll, tmpsonamebuf, res); ASSERT(res = 0);
h := Dl.dlopen(tmpsonamebuf, Dl.RTLD_LAZY + Dl.RTLD_GLOBAL);
END
END;
RETURN h
END TryDlOpen;
(* k8: FIXME: this completely wastes dll reference count! *)
PROCEDURE (VAR p: Platform) LoadDll (IN name: ARRAY OF CHAR; VAR ok: BOOLEAN);
(*VAR h: Dl.HANDLE; res: INTEGER; s: ARRAY Kernel.nameLen OF SHORTCHAR;*)
BEGIN
(*
ok := FALSE;
Utf.StringToUtf8(name, s, res); ASSERT(res = 0);
h := Dl.dlopen(s, Dl.RTLD_LAZY + Dl.RTLD_GLOBAL);
IF h # Dl.NULL THEN ok := TRUE END
*)
ok := (TryDlOpen(name) # Dl.NULL)
END LoadDll;
PROCEDURE (VAR p: Platform) ThisDllObj (mode, _: INTEGER; IN dll, name: ARRAY OF CHAR): INTEGER;
CONST mVar = 3; mProc = 4; (* sync with Kernel!! *)
VAR ad: INTEGER; h: Dl.HANDLE; res: INTEGER; s: ARRAY Kernel.nameLen OF SHORTCHAR;
BEGIN
ad := 0;
IF mode IN {mVar, mProc} THEN
(*
Utf.StringToUtf8(dll, s, res); ASSERT(res = 0);
h := Dl.dlopen(s, Dl.RTLD_LAZY + Dl.RTLD_GLOBAL);
*)
h := TryDlOpen(dll);
IF h # Dl.NULL THEN
Utf.StringToUtf8(name, s, res); ASSERT(res = 0);
ad := Dl.dlsym(h, s)
END
END;
RETURN ad
END ThisDllObj;
что делает: позволяет во многих случаях иметь один модуль импорта для win/lin. логика такая: отрезаем ".dll", если есть. если в конце нет ".so" — то добавляем. если в начале нет "lib" — то приставляем. пытаемся загрузить что получилось. если не вышло — пытаемся загрузить без приставленого "lib". если опять не вышло — пытаемся загрузить с оригинальным именем. в итоге имеем:
Код:
MODULE SQLiteLib ["sqlite3.dll"];
которое работает и в винде, и в линуксах.
в принципе, в виндокернел надо бы добавить нечто похожее, только наоборот. ;-) то есть, отрезать "lib" и ".so", если есть.
p.s.: а, да. ещё два глобала, чтобы в стек не гадить почём зря (всё равно у нас один поток):
Код:
(* k8: temporary buffer for .so names; should be protected for MT when it will appear *)
tmpsonamebuf: ARRAY 2048 OF SHORTCHAR;
tmpsonamebufL: ARRAY 2048 OF CHAR;