Л��чше день потерять, потом за пять минут долететь
Лучше день потерять, потом за пять минут долететь

Меня зовут Ярослав Бомбов и я более 30 лет занимаюсь созданием АСУТП. Как вы понимаете жизненные циклы в АСУТП штука длительная и иногда возникают задачи что-то добавить в систему работающую уже лет 20. И именно такой случай произошел - возникла необходимость изменить код в контроллере под управлением QNX4.

Можно конечно было поговорить на тему "вы в каком морге этого Франкенштейна получали туда и обращайтесь", но при ближайшем рассмотрении оказалось что код мой собственный ;). Самое простое решение открыть mcedit, что-то поправить и собрать в самом QNX4, но для начала надо вспомнить разобраться как все работает, а это удобней делать в современных IDE. Поиск бинарников OpenWatcom (OW) под линукс дал ровно два архива которые в моей системе не заработали. Поэтому решено действовать по принципу - лучше день потерять, потом за пять минут долететь.

Этап первый - Сборка

Исходники проекта доступны по адресу

Скачиваем, распаковываем

$ tar xvf open_watcom_1.9.0-src.tar.bz2

Все дерево исходников распаковывается в каталог OW19. Для начала, чтобы меньше чертыхаться в процессе рекомендую сразу после распаковки архива выполнить две команды раздающие необходимые права (с комфортным запасом).

$ chmod 755 .sh

$ chmod +w -R

Заглянув в скрипт build.sh который должен все установить автоматически понимаем что будет три подэтапа сборки (заодно исправляем в первой строчке #!/bin/sh на #!/bin/bash)

  1. сборка wmake с помощью утилит системы

  2. сборка builder при помощи wmake и попутно собираемых утилит open watcom

  3. сборка релиза билдером в подкаталог rel2

Итак приступим. Для начала можно запустить скрипт чтобы убедиться что он не проходит даже сборку wmake. Ошибки типа
c/mglob.c:118:10: error: #error Unknown CPU architecture
наводят на мысль что собрать в 64-х разрядном Debian 12 это не получится и нам нужна 32-х разрядная кухня.

$ sudo apt install binutils-multiarch
$ sudo apt install gcc-multilib
$ sudo apt install libc6-i386
$ sudo apt install gcc-multilib-i686-linux-gnu
$ sudo apt install libc6-dev-i386
в последующей сборке выяснилось, что еще понадобятся плюсы
$ sudo apt install g++-12-multilib-i686-linux-gnu

сразу добавляем в OW19/bld/wmake/gnumake строчку
CC=/usr/bin/i686-linux-gnu-gcc и через какое-то количество безуспешных попыток собрать остальное, попутно вникая в конфиги и логику работы wmake понимаем что в дистрибутиве есть OW19/bld/build/local/local.mif в который по замыслу создателей предназначен для всего что я задумал, а именно тонких настроек под среду компиляции.

находим эти три строчки
#common bootstrap definitions for Linux
!ifdef __LINUX__
!ifdef bootstrap

и изменяем нижеследующее в логике того что собираться все будет с помощью mulitilib утилит:

prefix=/usr/bin/i686-linux-gnu-
cc = $(prefix)gcc
cpp = $(prefix)g++-12
cl = $(cc)
bld_incs = $(bld_extra_incs) -I$(watcom_dir)/h
bld_cl = $(cc) $(bld_incs)
bld_cc = $(cc) $(bld_incs)
bld_link = $(cc)
librarian = $(prefix)ar

запускаем build.sh опять, довольно долго смотрим на бегущие строчки, что даже появляется надежда на успех, но нет опять выпали:

/usr/bin/ld: архитектура i386 входного файла «actions.obj» несовместима с выходным i386:x86-64
 .....
 collect2: error: ld returned 1 exit status
 Error(E42): Last command making (re2c.exe) returned a bad status
 Error(E02): Make execution terminated => non-zero return: 512

Вроде с архитектурами я договорился, но... опять вникать в мейкфайлы.
И в файле OW19/bld/re2c/master.mif обнаруживается секция с комментарием намекающим что проблема где-то рядом.

!ifdef bootstrap  
# awful hack to link this executable; if you know how to do this right, please do!
cl = g++
!endif

меняем строчку на
cl = /usr/bin/i686-linux-gnu-g++-12
и перезапускаем build.sh

И опять "это фиаско, братан"

cc loader.obj
 ../loader.c(45): Error! E1055: Unable to open 'os2.h'

Надо собрать под ПОЛУОСЬ?!!!
только не в мою смену...
в OW19/bld/w32loadr/prereq.ctl
комментируем

# wmake -h -f ../os2ldr/makefile prebuild=1
# os2ldr.exe /os2ldr.exe

дальнейшая сборка выдает еще две одинаковые ошибки об отсутствии библиотеки

 Warning! W1008: cannot open clib3r.lib : No such file or directory
 Error! E2028: memset_ is an undefined reference

которые чинятся добавление строчки
lflags_dll_linux_386 += libpath $(clib_dir)/library/linux.386/mf_r
в следующие два файла OW19/bld/dip/imp.mif
и в OW19/bld/mad/master.mif
как говорил выше один из создателей пакета я добавлю это сюда, если знаете как правильно - дайте мне знать.

Запускаем build.sh
И о чудо день потрачен не зря этап сборки завершен в каталоге rel2 свежий сияющий релиз OW19 с бинарниками работающими в моей системе (в теории).

Дочитавшим до сюда подарок - diff оригинального пакета к моим изменениям.

Скрытый текст
diff -r OW19/bld/build/local/local.mif OW19_ch/bld/build/local/local.mif
100,101c100,102
< cc = gcc
< cpp = gcc
---
> prefix=/usr/bin/i686-linux-gnu-
> cc = $(prefix)gcc
> cpp = $(prefix)g++-12
104,107c105,108
< bld_cl = gcc $(bld_incs)
< bld_cc = gcc $(bld_incs)
< bld_link = gcc
< librarian = ar
---
> bld_cl = $(cc) $(bld_incs)
> bld_cc = $(cc) $(bld_incs)
> bld_link = $(cc)
> librarian = $(prefix)ar
diff -r OW19/bld/dip/imp.mif OW19_ch/bld/dip/imp.mif
84c84
< 
---
> lflags_dll_linux_386 += libpath $(clib_dir)/library/linux.386/mf_r
diff -r OW19/bld/mad/master.mif OW19_ch/bld/mad/master.mif
83c83
< 
---
> lflags_dll_linux_386 += libpath $(clib_dir)/library/linux.386/mf_r
diff -r OW19/bld/re2c/master.mif OW19_ch/bld/re2c/master.mif
24c24
< cl = g++
---
> cl = /usr/bin/i686-linux-gnu-g++-12
diff -r OW19/bld/w32loadr/prereq.ctl OW19_ch/bld/w32loadr/prereq.ctl
24,25c24,25
<     wmake -h -f ../os2ldr/makefile prebuild=1
<     <CPCMD> os2ldr.exe <OWBINDIR>/os2ldr.exe
---
> #    wmake -h -f ../os2ldr/makefile prebuild=1
> #    <CPCMD> os2ldr.exe <OWBINDIR>/os2ldr.exe
diff -r OW19/bld/wmake/gnumake OW19_ch/bld/wmake/gnumake
3a4
> CC=/usr/bin/i686-linux-gnu-gcc
diff -r OW19/build.sh OW19_ch/build.sh
1c1
< #!/bin/sh
---
> #!/bin/bash

Проверим работоспособность сборки.
Перепишем из оригинальной системы /usr/watcom/10.6/usr/include/ и /usr/tcptk/4.25/usr/include/
в ~/worlspace/qnx4/include, а также /usr/watcom/10.6/usr/lib/ и /usr/tcptk/4.25/usr/lib/ в ~/worlspace/qnx4/lib

$ export WATCOM=/home/bj/workspace/watcom/OW19/rel2

$ wcl386 -bcl=QNX386 -mf -3r -i=. -i=../qnx4/include @hello.lnk hello.c

 loading object files
 searching libraries
 creating a QNX 32-bit executable

$ cat hello.lnk

 library clib3r.lib
 libpath ../qnx4/lib

$ cat hello.c

 #include

int main() {
 printf("Hello World!\n");
 return 0;
 }

Как выяснилось впоследствии утилита wcl386 немного странно работает с более сложными проектами чем hello world и лучше пользоваться раздельно компилятором wcc386 и линкером wlink.

Можно приступить к встраиванию всего этого в Eclipse и поскольку это не корпоративный блог и канала в телеге у меня нет, то это будет не в цикле статей, а прямо здесь.

Этап второй - Настраиваем сборку проекта в Eclipse

У меня установлены сам Эклипс и плагины:
Eclipse IDE for C/C++ Developers (includes Incubating components) Version: 2025-06 (4.36.0)
Eclipse IDE for C/C++ Developers
Eclipse IDE for Embedded C/C++ Developers
PyDev - Python IDE for Eclipse

Последний в рамках этой задачи вам вряд ли пригодится.

Создадим проект File\new\project C/C++ Project\C Managed Build название hello

На следующем шаге я убрал галочку с Debug (оставлю это желающим реализовать разные таргеты путем написания make файлов для каждого), а здесь будет только релиз и сразу в корень проекта.
Cross compiler prefix и Cross compiler path оставим пустыми, они нам не пригодятся.


Дабы создать видимость порядка перенесем в /opt бинарники Open Watcom и библиотеки QNX 4.25
/opt/qnx4
├── host
│ └── linux
│ └── binl
└── target
└── usr
├── include
│ ├── arpa
│ ├── net
│ ├── netinet
│ ├── photon
│ │ ├── contrib
│ │ └── realtime
│ ├── rpc
│ ├── snmp
│ ├── sys
│ └── windows
└── lib
└── src
└── startup

Возможно, для более сложных проектов в /opt/qnx4/host/linux придется еще что-то добавить из OW19/rel2/.

Я походил за вас по граблям с проектом с кодировкой UTF8 и попыткой понять почему программа успешно завершается, но ничего не выводит. Поэтому идем в свойства свежесозданного проекта.
Recource\Other - вбиваем CP866 или CP1251 или любую восьмибитную кодовую страницу, 866 в случае если будете пытаться печатать в QNX на русском, остальные восьмибитные будут влиять только на язык комментариев в исходниках и помогут без преобразований строк из UTF8 в ASCII перед выводом printf() получить что-либо печатное в консоли четверки латиницей.

Остальные настройки:

C/C++ Build\Builder Settings\Build Command – wmake
Убираем галочку с Generate Makefiles automatically.
Build directory: ${workspace_loc:/hello}

C/C++ Build\Environment
Добавляем в PATH /opt/qnx4/host/linux/binl
Создаем переменную WATCOM = /opt/qnx4/host/linux/

В принципе этого достаточно для компиляции, но чтобы правильно работал парсер IDE добавим путь к инклудам
C/C++ General\Path and Symbols\Includes\GNU C
Add directory path: /opt/qnx4/target/usr/include

C/C++ General\Preprocessor Include Path,Macros etc\Providers
Отключаем CDT Cross Built-in Compiler Settings

Чтобы показать подключение библиотек добавим в исходный код использование очередей mqueue, функций статистики и syslog.

hello.c
#include <stdio.h>
#include <sys/osinfo.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <syslog.h>

int main() {
	struct _osinfo  info;  
	struct mq_attr attr;
	mqd_t eventbox;
	attr.mq_flags=0;
	attr.mq_maxmsg=10;
	attr.mq_msgsize=sizeof(int);
	eventbox = mq_open("Event Box", O_WRONLY | O_CREAT, S_IRWXU, &attr);
	mq_unlink("Event Box");
	mq_close(eventbox);
	printf("result %i ",qnx_osinfo(0,&info));
	syslog(LOG_INFO,"Hello log\n\r");
	printf("Hello QNX version %i machine %s\n\r",info.version, info.machine);
    return 0;
}
Пишем Makefile
WCCFLAGS = -3r -mf -i=/opt/qnx4/target/usr/include -i=.
COMPILE =  $(CC) $(WCCFLAGS) 
CC = wcc386
CL = wcl386
LINK = wlink
all: hello
hello : hello.o
	$(LINK) name $@ file hello.o @hello.lnk
hello.o: hello.c 
	$(COMPILE) $<
clean: .SYMBOLIC 
	rm -f *.o
	rm -f hello
и hello.lnk
library mqueue3r.lib
libpath /opt/qnx4/target/usr/lib
system QNX386

Жмем на кнопку build и ура!

Консоль
12:03:00 **** Build of configuration Release for project hello **** 
wmake all
Open Watcom Make Version 1.9
Portions Copyright (c) 1988-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details. 	
    wcc386 -3r -mf -i=/opt/qnx4/target/usr/include -i=. hello.c 
Open Watcom C32 Optimizing Compiler Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved. 
Source code is available under the Sybase Open Watcom Public License. See http://www.openwatcom.org/ for details.
hello.c: 23 lines, included 1521, 0 warnings, 0 errors Code size: 160
 	wlink name hello file hello.o @hello.lnk 
Open Watcom Linker Version 1.9
Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. 
Source code is available under the Sybase Open Watcom Public License. See http://www.openwatcom.org/ for details.
loading object files 
searching libraries 
creating a QNX 32-bit executable 

12:03:00 Build Finished. 0 errors, 0 warnings. (took 74ms)

Теперь у нас есть свой лунапарк с блэкджеком..своя среда с гитлабом и ИИ агентами автокомплитом ;)
И работающий в QNX 4.25 артефакт

Задачу со звездочкой: построение полноценной кросскомпиляции оставлю вам, с налета у меня не получилось, а писать модуль поддержки Watcom в Eclipse у меня нет ни времени, ни желания, ни компетенций…

Как я уже говорил канала в телеге у меня нет, но если вдруг у вас остались вопросы, а здесь я не отвечаю, то можете меня попробовать там найти как (at)rusty_droid.