Пытаюсь скомпилировать такой код:
/*
BASS simple console player
Copyright (c) 1999-2015 Un4seen Developments Ltd.
*/
#include
#include
#define BASSDEF(f) (WINAPI *f) // define the functions as pointers
#include "bass.h"
#ifdef _WIN32 // Windows
#include
#else // OSX/Linux
#include
#include
#include
#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
#include
#include
#define BASSDEF(f) (WINAPI *f)
#include "bass.h"
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 is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-mingw32".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
.
Find the GDB manual and other documentation resources online at:
.
For help, type "help".
Type "apropos word" to search for commands related to "word".
This binary was built by Equation Solution ...
Reading symbols from qks.exe...done.
(gdb) b main
Breakpoint 1 at 0x4015c5: file qks.c, line 59.
(gdb) r -d -1 "C:\Users\user\Music\Radiohead\Creep.mp3"
Starting program: C:\Users\user\Documents\Projects\sound\qks.exe -d -1 "C:\Users\user\Music\Radiohead\Creep.mp3"
[New Thread 2708.0x16f4]
[New Thread 2708.0x4c0]
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 и студийный проект.