LINUX.ORG.RU

Wine: запустить unix process и подождать

 


0

2

Из окружения wine можно запускать линуксовые программы, хоть start /unix из шелла, хоть CreateProcess. Но есть одна проблема: подождать и получить код возврата невозможно. CreateProcess возвращает нуль вместо hProcess, start /wait /unix тоже не ждёт, _spawnl(_P_WAIT,…) тоже не ждёт, в общем всё плохо.

Есть способ как-то это обойти? Сделать какой-нибудь wrapper, который видит и libwine и posix (dll.so?), и чтобы он сделал posix_spawn и wait? Может кто-то уже делал?

Устроила бы альтернатива: среда с native компилятором mingw + всяким bash/coreutils/whatever, выполняющаяся успешно под wine. Msys2 не завёлся.

Если интересно, зачем это всё и где всплыло: хочу just for fun собирать SBCL for Windows кросс-компилятором mingw на линуксе. Всё неплохо работает, пока не доходит дело до contribs, где под виндовым sbcl.exe код хочет (run-program "cc"...) и (run-program "cat"...). И у меня упорное впечатление, что когда-то такое просто работало (в 2012 году я делал сборки под wine, эти вызовы там тогда уже были), но раскопки wine этому впечатлению противоречат (говорят, никогда не работало ожидание на unix processes).

Как вариант - сделать враппер, который это будет делать в обход wine (можно попробовать с помощью winegcc)

mittorn ★★★★★
()

winelib'овские исполняемые бинари запускаются как линуксовые без ожидания (даже если было указано -mconsole), так что скорее всего только путём загрузки dll.so

mittorn ★★★★★
()
Ответ на: комментарий от mittorn

а у меня вроде получилось: исходник с posix_spawn, winegcc даёт a.out.so, я на него делаю симлинк sleep.exe, и этот sleep.exe успешно ожидается из CreateProcess (и всякие прочие извраты с ним работают, типа CREATE_SUSPENDED и поместить в Job…)

не получалось, когда я из бинаря делал execve – как я понимаю это воспринималось как выход из дочернего процесса сразу.

LeninGad
() автор топика
Ответ на: комментарий от LeninGad

У меня «как есть» не заработало, но заработала такая конструкция:
Виндовое приложение:
/usr/lib/mingw64-toolchain/bin/x86_64-w64-mingw32-gcc wine-wrap.c -o wine-wrap.exe -mconsole

#include <stdio.h>
#include <windows.h>
int main(int argc, char **argv)
{
        printf("winegcc test\n");
        void *dll = LoadLibraryA("wine-wrap.dll.so");
        printf("dll %x\n", dll);
        int (*wrap)(const char*) = (void*)GetProcAddress(dll, "wrap");
        int r = wrap(argv[1]);
        printf("ret %d\n", r);
        return r;
}

Линуксовая dll:
gcc wine-wrap2.c -c -fPIC
#include <stdlib.h>
#include <stdio.h>
int unix_wrap(char *arg)
{
    printf("unix_wrap %s\n", arg);
    return system(arg);
}

winegcc wine-wrap3.c wine-wrap2.o -o wine-wrap.dll wine-wrap3.dll.spec -shared
wine-wrap3.dll.spec
@ cdecl -arch=x86_64 wrap(ptr) wrap

wine-wrap3.c
#include <windef.h>
#include <stdio.h>
BOOL WINAPI DllMain(INT par1, INT par2)
{
        printf("Here is DllMain, par1=%d, par2=%d\n", par1, par2);
        return TRUE;
}

extern int unix_wrap(char *arg);
int WINAPI wrap(char *arg)
{
        printf("wrap %s", arg);
        return unix_wrap(arg);
}

Вызов exe из консоли дожидается дочернего процесса и возвращает его результат.
stdout не перехватывается - тут скорее всего понадобится процесс-прокси делать, копирующий между юниксовым и виндовым пайпом

mittorn ★★★★★
()
Последнее исправление: mittorn (всего исправлений: 1)
Ответ на: комментарий от mittorn

У меня примерно вот такое, делал winegcc -mconsole, симлинк cc.exe на a.out.so, когда запускается, ищет «cc» в PATH.

Не работает с wineconsole (не ждёт, не прокидывается i/o, точнее i/o идёт на stdout процесса wineconsole), но при этом отлично работает в консольном приложении, запущенном без wineconsole и отлично ждёт по CreateProcess/WaitForSingleObject(hProcess). Для текущих нужд хватает.

#include <stdio.h>
#include <spawn.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[], char *envp[])
{
  
  char *me = argv[0];
  size_t len = strlen(me);

  if (len>65535) {
    return 255;
  }

  int dot = (int)len, slash = 0;

  for (int i = (int)len-1; i>0; i--) {
    if (me[i]=='/' || me[i]=='\\') {
      slash = i;
      break;
    }
    if (me[i]=='.') {
      dot = i;
    }
  }

  me[dot] = '\0';
  argv[0] = me+slash;

  pid_t child;
  int rc = posix_spawnp(&child, argv[0], NULL, NULL, argv, envp);
  // printf("posix_spawn: %d\n", rc);
  if (rc) {
    errno = rc;
    perror("posix_spawn");
    return 255;
  }
  int wstatus;
  for (;;) {
    pid_t wr = waitpid(child, &wstatus,0);
    if (wr == -1) {
      if (errno!=EINTR)
	return 255;
    }
    if (WIFEXITED(wstatus)) {
      return WEXITSTATUS(wstatus);
    }
  }
}
LeninGad
() автор топика
Ответ на: комментарий от LeninGad

Вилимо. это потому что -mconsole не полностью работает в elf бинарях (либо надо было переименовать просто в exe вместо exe.so)
Но мой варинат запуска из консольного exe, собранного mingw работает

mittorn ★★★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.