Пытаюсь скомпилировать такой код:
/*
BASS simple console player
Copyright (c) 1999-2015 Un4seen Developments Ltd.
*/
#include
#ifdef _WIN32 // Windows
#include
#define Sleep(x) usleep(x*1000)
int _kbhit()
{
int r;
fd_set rfds;
struct timeval tv={0};
struct termios term,oterm;
tcgetattr(0,&oterm);
memcpy(&term,&oterm,sizeof(term));
cfmakeraw(&term);
tcsetattr(0,TCSANOW,&term);
FD_ZERO(&rfds);
FD_SET(0,&rfds);
r=select(1,&rfds,NULL,NULL,&tv);
tcsetattr(0,TCSANOW,&oterm);
return r;
}
#endif
// display error messages
void Error(const char *text)
{
printf("Error(%d): %s
",BASS_ErrorGetCode(),text);
BASS_Free();
exit(0);
}
void ListDevices()
{
BASS_DEVICEINFO di;
int a;
for (a=1;BASS_GetDeviceInfo(a,&di);a++) {
if (di.flags&BASS_DEVICE_ENABLED) // enabled output device
printf("dev %d: %s
",a,di.name);
}
}
void main(int argc, char **argv)
{
DWORD chan,act,time,level;
BOOL ismod;
QWORD pos;
int a,device=-1;
printf("Simple console mode BASS example : MOD/MPx/OGG/WAV player
"
"---------------------------------------------------------
");
// check the correct BASS was loaded
if (HIWORD(BASS_GetVersion())!=BASSVERSION) {
printf("An incorrect version of BASS was loaded");
return;
}
for (a=1;a
"
"\t-l = list devices
"
"\t-d = device number
");
return;
}
// initialize output device
if (!BASS_Init(device,44100,0,0,NULL))
Error("Can't initialize device");
// try streaming the file/url
if ((chan=BASS_StreamCreateFile(FALSE,argv[argc-1],0,0,BASS_SAMPLE_LOOP))
|| (chan=BASS_StreamCreateURL(argv[argc-1],0,BASS_SAMPLE_LOOP,0,0))) {
pos=BASS_ChannelGetLength(chan,BASS_POS_BYTE);
if (BASS_StreamGetFilePosition(chan,BASS_FILEPOS_DOWNLOAD)!=-1) {
// streaming from the internet
if (pos!=-1)
#ifdef _WIN32
printf("streaming internet file [%I64d bytes]",pos);
#else
printf("streaming internet file [%lld bytes]",pos);
#endif
else
printf("streaming internet file");
} else
#ifdef _WIN32
printf("streaming file [%I64d bytes]",pos);
#else
printf("streaming file [%lld bytes]",pos);
#endif
ismod=FALSE;
} else {
// try loading the MOD (with looping, sensitive ramping, and calculate the duration)
if (!(chan=BASS_MusicLoad(FALSE,argv[argc-1],0,0,BASS_SAMPLE_LOOP|BASS_MUSIC_RAMPS|BASS_MUSIC_PRESCAN,1)))
// not a MOD either
Error("Can't play the file");
{ // count channels
float dummy;
for (a=0;BASS_ChannelGetAttribute(chan,BASS_ATTRIB_MUSIC_VOL_CHAN+a,&dummy);a++);
}
printf("playing MOD music \"%s\" [%u chans, %u orders]",
BASS_ChannelGetTags(chan,BASS_TAG_MUSIC_NAME),a,(DWORD)BASS_ChannelGetLength(chan,BASS_POS_MUSIC_ORDER));
pos=BASS_ChannelGetLength(chan,BASS_POS_BYTE);
ismod=TRUE;
}
// display the time length
if (pos!=-1) {
time=(DWORD)BASS_ChannelBytes2Seconds(chan,pos);
printf(" %u:%02u
",time/60,time%60);
} else // no time length available
printf("
");
BASS_ChannelPlay(chan,FALSE);
while (!_kbhit() && (act=BASS_ChannelIsActive(chan))) {
// display some stuff and wait a bit
level=BASS_ChannelGetLevel(chan);
pos=BASS_ChannelGetPosition(chan,BASS_POS_BYTE);
time=BASS_ChannelBytes2Seconds(chan,pos);
#ifdef _WIN32
printf("pos %09I64u",pos);
#else
printf("pos %09llu",pos);
#endif
if (ismod) {
pos=BASS_ChannelGetPosition(chan,BASS_POS_MUSIC_ORDER);
printf(" (%03u:%03u)",LOWORD(pos),HIWORD(pos));
}
printf(" - %u:%02u - L ",time/60,time%60);
if (act==BASS_ACTIVE_STALLED) { // playback has stalled
printf("-- buffering : %05u --",(DWORD)BASS_StreamGetFilePosition(chan,BASS_FILEPOS_BUFFER));
} else {
for (a=27204;a>200;a=a*2/3) putchar(LOWORD(level)>=a?'*':'-');
putchar(' ');
for (a=210;a<32768;a=a*3/2) putchar(HIWORD(level)>=a?'*':'-');
}
printf(" R - cpu %.2f%%
",BASS_GetCPU());
fflush(stdout);
Sleep(50);
}
printf("
");
// wind the frequency down...
BASS_ChannelSlideAttribute(chan,BASS_ATTRIB_FREQ,1000,500);
Sleep(300);
// ...and fade-out to avoid a "click"
BASS_ChannelSlideAttribute(chan,BASS_ATTRIB_VOL,-1,200);
// wait for slide to finish
while (BASS_ChannelIsSliding(chan,0)) Sleep(1);
BASS_Free();
}
Этот пример доступен из коробки. От себя добавил только
#define BASSDEF(f) (WINAPI* f) // define the functions as pointers
иначе не собиралось. После запуска программа, не открывая окно, сразу падает. gdb пишет
Program received signal SIGSEGV, Segmentation fault.
0x00000000 in ?? ()
(gdb) bt
#0 0x00000000 in ?? ()
#1 0x004015c1 in main (argc=1, argv=0xdc15b0) at qks.c:68
Даже этот пример не работает:
#define BASSDEF(f) (WINAPI *f)
#include "bass.h"
int main() {
BASS_Init(-1, 44100, 0, 0, NULL);
}
Компилирую так:
gcc.exe -m32 -Wall -Wextra -Wpedantic -lbass -mwindows qks.c -o qks.exe
ОС - Windows 10 x64; GCC - 4.9.2
UPD
Появился небольшой прогресс. Эта программа компилируется и успешно завершается:
#include
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow) {
(void) hPrevInstance, (void) lpCmdLine, (void) nCmdShow;
HINSTANCE bass=LoadLibrary("bass.dll"); // load BASS
BASS_Init=GetProcAddress(bass,"BASS_Init"); // get BASS_Init
BASS_Init(-1,44100,0,NULL,NULL) // call BASS_Init
}
Вот что написано в документации:
The downside is that you have to manually import each function that
you use, with the GetProcAddress function. But it has been made a lot
simpler to import BASS this way by the use of the BASSDEF #define.
Here's a small example:
#define BASSDEF(f) (WINAPI *f) // define the functions as pointers
#include "bass.h" ... HINSTANCE bass=LoadLibrary("BASS.DLL"); // load BASS
BASS_Init=GetProcAddress(bass,"BASS_Init"); // get BASS_Init
BASS_Init(-1,44100,0,hWnd,NULL); // call BASS_Init
Однако при попытке получить адрес других функций ловлю предупреждение:
warning: assignment from incompatible pointer type
BASS_GetVersion=GetProcAddress(bass,"BASS_GetVersion");
И если вызвать эту функцию (или какие-нибудь другие), то снова происходит SIGSEGV
UPD 2
Приведенный выше пример работает, если добавит в начало тела main эти строки:
HINSTANCE bass=LoadLibrary("bass.dll"); // load BASS
BASS_Init=GetProcAddress(bass,"BASS_Init"); // get BASS_Init
BASS_GetVersion=GetProcAddress(bass,"BASS_GetVersion");
BASS_Free=GetProcAddress(bass,"BASS_Free");
BASS_SetVolume=GetProcAddress(bass,"BASS_SetVolume");
BASS_SetConfig=GetProcAddress(bass,"BASS_SetConfig");
BASS_SampleFree=GetProcAddress(bass,"BASS_SampleFree");
BASS_SampleLoad=GetProcAddress(bass,"BASS_SampleLoad");
BASS_SampleGetChannel=GetProcAddress(bass,"BASS_SampleGetChannel");
BASS_ChannelPlay=GetProcAddress(bass,"BASS_ChannelPlay");
BASS_ChannelStop=GetProcAddress(bass,"BASS_ChannelStop");
BASS_GetVolume=GetProcAddress(bass,"BASS_GetVolume");
BASS_GetVersion=GetProcAddress(bass,"BASS_GetVersion");
BASS_GetCPU=GetProcAddress(bass,"BASS_GetCPU");
BASS_Pause=GetProcAddress(bass,"BASS_Pause");
BASS_Start=GetProcAddress(bass,"BASS_Start");
BASS_MusicFree=GetProcAddress(bass,"BASS_MusicFree");
BASS_MusicLoad=GetProcAddress(bass,"BASS_MusicLoad");
BASS_ChannelSetAttribute=GetProcAddress(bass,"BASS_ChannelSetAttribute");
BASS_StreamCreateFile=GetProcAddress(bass,"BASS_StreamCreateFile");
BASS_ErrorGetCode=GetProcAddress(bass,"BASS_ErrorGetCode");
BASS_StreamCreateURL=GetProcAddress(bass, "BASS_StreamCreateURL");
BASS_ChannelGetLength=GetProcAddress(bass, "BASS_ChannelGetLength");
BASS_StreamGetFilePosition=GetProcAddress(bass, "BASS_StreamGetFilePosition");
BASS_ChannelGetAttribute=GetProcAddress(bass, "BASS_ChannelGetAttribute");
BASS_ChannelGetTags=GetProcAddress(bass, "BASS_ChannelGetTags");
BASS_ChannelGetLength=GetProcAddress(bass, "BASS_ChannelGetLength");
BASS_ChannelBytes2Seconds=GetProcAddress(bass, "BASS_ChannelBytes2Seconds");
BASS_ChannelIsActive=GetProcAddress(bass, "BASS_ChannelIsActive");
BASS_ChannelGetLevel=GetProcAddress(bass, "BASS_ChannelGetLevel");
BASS_ChannelGetPosition=GetProcAddress(bass, "BASS_ChannelGetPosition");
BASS_ChannelSlideAttribute=GetProcAddress(bass, "BASS_ChannelSlideAttribute");
Одно большое "НО":
Звук воспроизводиться при запуске из командной строки (cmd.exe, ConEmu), но нет текстовой информации. Т.е. я запускаю программу и она работает в фоне, в терминале сразу появляется приглашение ввода:
user@LAPTOP-OIQUIP0K C:\Users\user\Documents\Projects\sound
> qks.exe -d -1 "C:\Users\user\Music\Radiohead\Creep.mp3"
user@LAPTOP-OIQUIP0K C:\Users\user\Documents\Projects\sound
>
Однако вся текстовая информация (звук тоже работает) появляется во встроенной консоли SublimeText 3
C:\Users\user\Documents\Projects\sound>qks.exe -d -1 "C:\Users\user\Music\Radiohead\Creep.mp3"
Simple console mode BASS example : MOD/MPx/OGG/WAV player
---------------------------------------------------------
streaming file [41587200 bytes] 3:55
pos 000000136 - 0:00 - L ------------- ------------- R - cpu 0.00%
pos 000005944 - 0:00 - L ------------- ------------- R - cpu 0.00%
pos 000014808 - 0:00 - L ------------- ------------- R - cpu 0.00%
pos 000023728 - 0:00 - L ------------- ------------- R - cpu 0.00%
pos 000032628 - 0:00 - L ------------- ------------- R - cpu 0.07%
pos 000041584 - 0:00 - L ---********** **********--- R - cpu 0.07%
pos 000050496 - 0:00 - L -----******** ********----- R - cpu 0.14%
pos 000059536 - 0:00 - L -----******** *********---- R - cpu 0.14%
pos 000068572 - 0:00 - L -----******** *********---- R - cpu 0.19%
pos 000077544 - 0:00 - L -----******** ********----- R - cpu 0.19%
pos 000086464 - 0:00 - L -----******** *********---- R - cpu 0.25%
pos 000095364 - 0:00 - L -----******** ********----- R - cpu 0.25%
...
Информация о компиляторе (gcc -v):
Using built-in specs.
COLLECT_GCC=gcc.exe
COLLECT_LTO_WRAPPER=c:/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/4.8.1/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../../../src/gcc-4.8.1/configure --build=x86_64-w64-mingw32 --enable-targets=all --enable-languages=ada,c,c++,fortran,lto,objc,obj-c++ --enable-libgomp --enable-lto --enable-graphite --enable-cxx-flags=-DWINPTHREAD_STATIC --enable-libstdcxx-debug --enable-threads=posix --enable-version-specific-runtime-libs --enable-fully-dynamic-string --enable-libstdcxx-threads --enable-libstdcxx-time --with-gnu-ld --disable-werror --disable-nls --disable-win32-registry --prefix=/mingw64tdm --with-local-prefix=/mingw64tdm --with-pkgversion=tdm64-2 --with-bugurl=http://tdm-gcc.tdragon.net/bugs
Thread model: posix
gcc version 4.8.1 (tdm64-2)
Отладка:
user@LAPTOP-OIQUIP0K C:\Users\user\Documents\Projects\sound
> gdb.exe qks.exe
GNU gdb (GDB) 7.7.50.20140303-cvs
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This binary was built by Equation Solution
Breakpoint 1, main (argc=4, argv=0xab2390) at qks.c:59
59 HINSTANCE bass=LoadLibrary("bass.dll"); // load BASS
(gdb) n
[New Thread 2708.0xd28]
60 BASS_Init=GetProcAddress(bass,"BASS_Init"); // get BASS_Init
(gdb)
61 BASS_GetVersion=GetProcAddress(bass,"BASS_GetVersion");
(gdb)
62 BASS_Free=GetProcAddress(bass,"BASS_Free");
(gdb)
63 BASS_SetVolume=GetProcAddress(bass,"BASS_SetVolume");
(gdb)
64 BASS_SetConfig=GetProcAddress(bass,"BASS_SetConfig");
(gdb)
65 BASS_SampleFree=GetProcAddress(bass,"BASS_SampleFree");
(gdb)
66 BASS_SampleLoad=GetProcAddress(bass,"BASS_SampleLoad");
(gdb)
67 BASS_SampleGetChannel=GetProcAddress(bass,"BASS_SampleGetChannel");
(gdb)
68 BASS_ChannelPlay=GetProcAddress(bass,"BASS_ChannelPlay");
(gdb)
69 BASS_ChannelStop=GetProcAddress(bass,"BASS_ChannelStop");
(gdb)
70 BASS_GetVolume=GetProcAddress(bass,"BASS_GetVolume");
(gdb)
71 BASS_GetVersion=GetProcAddress(bass,"BASS_GetVersion");
(gdb)
72 BASS_GetCPU=GetProcAddress(bass,"BASS_GetCPU");
(gdb)
73 BASS_Pause=GetProcAddress(bass,"BASS_Pause");
(gdb)
74 BASS_Start=GetProcAddress(bass,"BASS_Start");
(gdb)
75 BASS_MusicFree=GetProcAddress(bass,"BASS_MusicFree");
(gdb)
76 BASS_MusicLoad=GetProcAddress(bass,"BASS_MusicLoad");
(gdb)
77 BASS_ChannelSetAttribute=GetProcAddress(bass,"BASS_ChannelSetAttribute");
(gdb)
78 BASS_StreamCreateFile=GetProcAddress(bass,"BASS_StreamCreateFile");
(gdb)
79 BASS_ErrorGetCode=GetProcAddress(bass,"BASS_ErrorGetCode");
(gdb)
80 BASS_StreamCreateURL=GetProcAddress(bass, "BASS_StreamCreateURL");
(gdb)
81 BASS_ChannelGetLength=GetProcAddress(bass, "BASS_ChannelGetLength");
(gdb)
82 BASS_StreamGetFilePosition=GetProcAddress(bass, "BASS_StreamGetFilePosition");
(gdb)
83 BASS_ChannelGetAttribute=GetProcAddress(bass, "BASS_ChannelGetAttribute");
(gdb)
84 BASS_ChannelGetTags=GetProcAddress(bass, "BASS_ChannelGetTags");
(gdb)
85 BASS_ChannelGetLength=GetProcAddress(bass, "BASS_ChannelGetLength");
(gdb)
86 BASS_ChannelBytes2Seconds=GetProcAddress(bass, "BASS_ChannelBytes2Seconds");
(gdb)
87 BASS_ChannelIsActive=GetProcAddress(bass, "BASS_ChannelIsActive");
(gdb)
88 BASS_ChannelGetLevel=GetProcAddress(bass, "BASS_ChannelGetLevel");
(gdb)
89 BASS_ChannelGetPosition=GetProcAddress(bass, "BASS_ChannelGetPosition");
(gdb)
90 BASS_ChannelSlideAttribute=GetProcAddress(bass, "BASS_ChannelSlideAttribute");
(gdb)
95 int a,device=-1;
(gdb)
97 printf("Simple console mode BASS example : MOD/MPx/OGG/WAV player
"
(gdb)
101 if (HIWORD(BASS_GetVersion())!=BASSVERSION) {
(gdb)
0x744d59c6 in ?? ()
(gdb) ni
0x744b10f9 in ?? () from C:\Users\user\Documents\Projects\sound\bass.dll
(gdb)
0x744b45c5 in ?? () from C:\Users\user\Documents\Projects\sound\bass.dll
(gdb)
0x744b45c6 in ?? () from C:\Users\user\Documents\Projects\sound\bass.dll
(gdb)
0x744b45cc in ?? () from C:\Users\user\Documents\Projects\sound\bass.dll
(gdb)
0x744b45d2 in ?? () from C:\Users\user\Documents\Projects\sound\bass.dll
(gdb)
0x744b45d4 in ?? () from C:\Users\user\Documents\Projects\sound\bass.dll
(gdb)
0x744b45d6 in ?? () from C:\Users\user\Documents\Projects\sound\bass.dll
(gdb)
0x744b45ee in ?? () from C:\Users\user\Documents\Projects\sound\bass.dll
(gdb)
0x744b45f0 in ?? () from C:\Users\user\Documents\Projects\sound\bass.dll
(gdb)
0x744b45f1 in ?? () from C:\Users\user\Documents\Projects\sound\bass.dll
(gdb)
0x744b10fe in ?? () from C:\Users\user\Documents\Projects\sound\bass.dll
(gdb)
0x744b1101 in ?? () from C:\Users\user\Documents\Projects\sound\bass.dll
(gdb)
0x744b1103 in ?? () from C:\Users\user\Documents\Projects\sound\bass.dll
(gdb)
0x744b1104 in ?? () from C:\Users\user\Documents\Projects\sound\bass.dll
(gdb)
0x744d59cb in ?? ()
(gdb)
0x744d59d0 in ?? ()
(gdb)
0x00401976 in main (argc=4, argv=0xab2390) at qks.c:101
101 if (HIWORD(BASS_GetVersion())!=BASSVERSION) {
(gdb) n
106 for (a=1;a
OS: Windows 10 x64
CPU: AMD A9-9410 RADEON R5, COMPUTE CORES 2C+3G 2.90 GHz
Команды компиляции и запуска:
gcc.exe -g -std=c11 -m32 -Wall -Wextra -Wpedantic -lbass -mwindows qks.c -o qks.exe
qks.exe -d -1 "C:\Users\user\Music\Eminem\Rap God.mp3"
Ответ
Есть такая штука - ABI - то есть описание того, как функция/класс будет представлена в бинарном виде. Это очень важно, когда линкуются два разных куска кода (например, exe и статическая библиотка) или просто вызываются (например, обращение к dll). В некоторых случаях линковщик (а это его работа) может проверить, что интерфейс не совпадает и поднять панику. А может и не знать или проигнорировать.
Если два куска кода не совместимы на уровне ABI, то может произойти все что угодно. Самый простой пример - вызывающая сторона ожидает параметры в регистрах, а вызываемая - в стеке. Что именно прочитается со стека - никто не знает. В лучшем случае упадет с Access violation.
В случае чистого Си эту проблему достаточно хорошо решили (всякие stdcall, cdecl и подобное). А вот в случае с++ все сильно сложнее - есть классы, а им нужно хранить данные, которые никак не стандартизированы. Даже если использовать только gcc, он может использовать различное ABI. Из последнего, на что я лично натолкнулся, это сильно измененный ABI при переходе от 4.9.х на 5.4.х (он вроде после 5.2 поменялся). Здесь есть много деталей.
Теперь ближе к проблеме. По внешнему виду файла обычно сложно догадаться, какой версией компилятора он собран. Но её можно попробовать угадать. Судя по всему, там внутри все собрано с помощью vc6 (это очень древнее существо) и более-менее свежие gcc с ним поэтому и не совместимы. А старые - да. @VadimTagil просто повезло, что он угадал правильную версию.
Что делать? использовать gcc 3.4 как не очень, как по мне, поэтому, лучше взять сорцы и пересобрать их именно тем gcc, которым будет собираться все остальное. Благое дело, там есть makefile и студийный проект.
Комментариев нет:
Отправить комментарий