试图在Mac上使用Eclipse编译OpenAL,结果在符号(s)中找不到架构x86_64错误

Trying to Compile OpenAL on Mac using Eclipse Results in symbol(s) not found for architecture x86_64 Error

本文关键字:找不到 x86 错误 结果 Mac Eclipse OpenAL 编译 符号      更新时间:2023-10-16

我对c++相当陌生,但我一直想用音频制作一个程序,我找到了OpenAL。作为参考,我正在使用Eclipse和运行OS X 10.10的Mac。我找到了一个简单的教程程序:

#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <GLUT/glut.h>
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
ALCdevice *dev;
ALCcontext *ctx;
struct stat statbuf;
if(argc < 2)
{
    fprintf(stderr, "Usage: %s <audiofile>n", argv[0]);
    return 0;
}
/* First the standard open-device, create-context, set-context.. */
dev = alcOpenDevice(NULL);
if(!dev)
{
    fprintf(stderr, "Oopsn");
    return 1;
}
ctx = alcCreateContext(dev, NULL);
alcMakeContextCurrent(ctx);
if(!ctx)
{
    fprintf(stderr, "Oops2n");
    return 1;
}
{
    /* The number of buffers and bytes-per-buffer for our stream are set
     * here. The number of buffers should be two or more, and the buffer
     * size should be a multiple of the frame size (by default, OpenAL's
     * largest frame size is 4, however extensions that can add more formats
     * may be larger). Slower systems may need more buffers/larger buffer
     * sizes. */
#define NUM_BUFFERS 3
#define BUFFER_SIZE 4096
    /* These are what we'll use for OpenAL playback */
    ALuint source, buffers[NUM_BUFFERS];
    ALuint frequency;
    ALenum format;
    unsigned char *buf;
    /* These are used for interacting with mplayer */
    int pid, files[2];
    FILE *f;
    /* Generate the buffers and sources */
    alGenBuffers(NUM_BUFFERS, buffers);
    alGenSources(1, &source);
    if(alGetError() != AL_NO_ERROR)
    {
        fprintf(stderr, "Error generating :(n");
        return 1;
    }
    /* Here's where our magic begins. First, we want to call stat on the
     * filename since mplayer will just silently exit if it tries to play a
     * non-existant file **/
    if(stat(argv[1], &statbuf) != 0 || !S_ISREG(statbuf.st_mode))
    {
        fprintf(stderr, "%s doesn't seem to be a regular file :(n", argv[1]);
        return 1;
    }
    /* Open a file pipe. This will create two file-descriptors, one for
     * reading and another for writing. The data will be passed in memory,
     * so it won't be bogged by disk access. */
    if(pipe(files) != 0)
    {
        fprintf(stderr, "Pipe failed :(n");
        return 1;
    }
    /* Now we fork. The forked process will inherit the original process's
     * file descriptors, so each process will have access to the same pipe.
     * Note that the process memory isn't shared (if you change something in
     * one process, the other will be unaffected). */
    pid = fork();
    switch(pid)
    {
        case -1:
            /* If it returns -1, there was an error */
            fprintf(stderr, "Fork failed :(n");
            return 1;
            break;
        case 0:
            /* Returning 0 means that we're now in the child process, that
             * we'll turn into mplayer. First, we can close the read file
             * descriptor since this process won't be reading from it. */
            close(files[0]);
            /* Here's part of the trick. After closing the stdout file
             * descriptor, dup2 assigns it the pipe's write file descriptor.
             * So now, whenever anything writes to stdout, it'll go to the
             * pipe instead! */
            close(STDOUT_FILENO);
            dup2(files[1], STDOUT_FILENO);
            /* We can use execlp to run mplayer with the options we need. To
             * output audio as a standard .wav-formatted file, we use the
             * pcm audio-out device, and tell it to write to stdout. By
             * running this, we overwrite the current process memory with
             * the named commmand, which causes it to start mplayer with the
             * overridden stdout */
            execlp("mplayer", "-nogui", "-really-quiet", "-novideo",
                   "-noconsolecontrols", "-ao", "pcm:file=/dev/stdout",
                   argv[1], (char*)NULL);
            /* The exec* functions should never return. If it does,
             * something went wrong, so just _exit. */
            _exit(1);
        default:
            /* Any other return value means we're in the parent process.
             * Here, we don't need the write file descriptor, so close it.
             * Now we can begin using the read file descriptor to read
             * mplayer's stdout, which will be the file decoded in real-
             * time! */
            close(files[1]);
            break;
    }
    /* fdopen simply creates a FILE* from the given file descriptor. This is
     * generally easier to work with, but there's no reason you couldn't use
     * the lower-level io routines on the descriptor if you wanted */
    f = fdopen(files[0], "rb");
    /* Allocate the buffer, and read the RIFF-WAVE header. We don't actually
     * need to read it, so just ignore what it writes to the buffer. Because
     * this is a file pipe, it is unseekable, so we have to read bytes we
     * want to skip. Also note that because mplayer is writing out the file
     * in real-time, the chunk size information may not be filled out. */
    malloc(BUFFER_SIZE);
    fread(buf, 1, 12, f);
    /* This is the first .wav file chunk. Check the chunk header to make
     * sure it is the format information. The first four bytes is the
     * indentifier (which we check), and the last four is the chunk size
     * (which we ignore) */
    fread(buf, 1, 8, f);
    if(buf[0] != 'f' || buf[1] != 'm' || buf[2] != 't' || buf[3] != ' ')
    {
        /* If this isn't the format info, it probably means it was an
         * unsupported audio format for mplayer, or the file didn't contain
         * an audio track. */
        fprintf(stderr, "Not 'fmt ' :(n");
        /* Note that closing the file will leave mplayer's write file
         * descriptor without a read counterpart. This will cause mplayer to
         * receive a SIGPIPE signal, which will cause it to abort and exit
         * automatically for us. Alternatively, you can use the pid returned
         * from fork() to send it a signal explicitly. */
        fclose(f);
        return 1;
    }
    {
        int channels, bits;
        /* Read the wave format type, as a 16-bit little-endian integer.
         * There's no reason this shouldn't be 1. */
        fread(buf, 1, 2, f);
        if(buf[1] != 0 || buf[0] != 1)
        {
            fprintf(stderr, "Not PCM :(n");
            fclose(f);
            return 1;
        }
        /* Get the channel count (16-bit little-endian) */
        fread(buf, 1, 2, f);
        channels  = buf[1]<<8;
        channels |= buf[0];
        /* Get the sample frequency (32-bit little-endian) */
        fread(buf, 1, 4, f);
        frequency  = buf[3]<<24;
        frequency |= buf[2]<<16;
        frequency |= buf[1]<<8;
        frequency |= buf[0];
        /* The next 6 bytes hold the block size and bytes-per-second. We
         * don't need that info, so just read and ignore it. */
        fread(buf, 1, 6, f);
        /* Get the bit depth (16-bit little-endian) */
        fread(buf, 1, 2, f);
        bits  = buf[1]<<8;
        bits |= buf[0];
        /* Now convert the given channel count and bit depth into an OpenAL
         * format. We could use extensions to support more formats (eg.
         * surround sound, floating-point samples), but that is beyond the
         * scope of this tutorial */
        format = 0;
        if(bits == 8)
        {
            if(channels == 1)
                format = AL_FORMAT_MONO8;
            else if(channels == 2)
                format = AL_FORMAT_STEREO8;
        }
        else if(bits == 16)
        {
            if(channels == 1)
                format = AL_FORMAT_MONO16;
            else if(channels == 2)
                format = AL_FORMAT_STEREO16;
        }
        if(!format)
        {
            fprintf(stderr, "Incompatible format (%d, %d) :(n", channels, bits);
            fclose(f);
            return 1;
        }
    }
    /* Next up is the data chunk, which will hold the decoded sample data */
    fread(buf, 1, 8, f);
    if(buf[0] != 'd' || buf[1] != 'a' || buf[2] != 't' || buf[3] != 'a')
    {
        fclose(f);
        fprintf(stderr, "Not 'data' :(n");
        return 1;
    }
    /* Now we have everything we need. To read the decoded data, all we have
     * to do is read from the file handle! Note that the .wav format spec
     * has multibyte sample foramts stored as little-endian. If you were on
     * a big-endian machine, you'd have to iterate over the returned data
     * and flip the bytes for those formats before giving it to OpenAL. Also
     * be aware that there is no seeking on the file handle. A slightly more
     * complex setup could be made to send commands back to mplayer to seek
     * on the stream, however that is beyond the scope of this tutorial. */
    {
        int ret;
        /* Fill the data buffer with the amount of bytes-per-buffer, and
         * buffer it into OpenAL. This may read (and return) less than the
         * requested amount when it hits the end of the "stream" */
        ret = fread(buf, 1, BUFFER_SIZE, f);
        alBufferData(buffers[0], format, buf, ret, frequency);
        /* Once the data's buffered into OpenAL, we're free to modify our
         * data buffer, so reuse it to fill the remaining OpenAL buffers. */
        ret = fread(buf, 1, BUFFER_SIZE, f);
        alBufferData(buffers[1], format, buf, ret, frequency);
        ret = fread(buf, 1, BUFFER_SIZE, f);
        alBufferData(buffers[2], format, buf, ret, frequency);
        if(alGetError() != AL_NO_ERROR)
        {
            fprintf(stderr, "Error loading :(n");
            return 1;
        }
        /* Queue the buffers onto the source, and start playback! */
        alSourceQueueBuffers(source, NUM_BUFFERS, buffers);
        alSourcePlay(source);
        if(alGetError() != AL_NO_ERROR)
        {
            fprintf(stderr, "Error starting :(n");
            return 1;
        }
        /* While not at the end of the stream... */
        while(!feof(f))
        {
            ALuint buffer;
            ALint val;
            /* Check if OpenAL is done with any of the queued buffers */
            alGetSourcei(source, AL_BUFFERS_PROCESSED, &val);
            if(val <= 0)
                continue;
            /* For each processed buffer... */
            while(val--)
            {
                /* Read the next chunk of decoded data from the stream */
                ret = fread(buf, 1, BUFFER_SIZE, f);
                /* Pop the oldest queued buffer from the source, fill it
                 * with the new data, then requeue it */
                alSourceUnqueueBuffers(source, 1, &buffer);
                alBufferData(buffer, format, buf, ret, frequency);
                alSourceQueueBuffers(source, 1, &buffer);
                if(alGetError() != AL_NO_ERROR)
                {
                    fprintf(stderr, "Error buffering :(n");
                    return 1;
                }
            }
            /* Make sure the source is still playing, and restart it if
             * needed. */
            alGetSourcei(source, AL_SOURCE_STATE, &val);
            if(val != AL_PLAYING)
                alSourcePlay(source);
        }
    }
    /* File's done decoding. We can close the pipe and free the data buffer
     * now. */
    fclose(f);
    free(buf);
    {
        ALint val;
        /* Although mplayer is done giving us data, OpenAL may still be
         * playing the remaining buffers. Wait until it stops. */
        do {
            alGetSourcei(source, AL_SOURCE_STATE, &val);
        } while(val == AL_PLAYING);
    }
    /* Done playing. Delete the source and buffers */
    alDeleteSources(1, &source);
    alDeleteBuffers(NUM_BUFFERS, buffers);
}
/* All done. Close OpenAL and exit. */
alcMakeContextCurrent(NULL);
alcDestroyContext(ctx);
alcCloseDevice(dev);
return 0;
}

然而,当我试图编译这个程序时,我得到一个错误。下面是编译:

    19:25:37 **** Incremental Build of configuration Release for project AudioPlayer ****
make all 
Building file: ../src/main.cpp
Invoking: GCC C++ Compiler
g++ -I/usr/local/include/SDL2 -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/main.d" -MT"src/main.o" -o "src/main.o" "../src/main.cpp"
../src/main.cpp:146:15: warning: variable 'buf' is uninitialized when used here [-Wuninitialized]
        fread(buf, 1, 12, f);
              ^~~
../src/main.cpp:56:27: note: initialize the variable 'buf' to silence this warning
        unsigned char *buf;
                          ^
                           = NULL
1 warning generated.
Finished building: ../src/main.cpp
Building target: AudioPlayer
Invoking: MacOS X C++ Linker
g++ -L/usr/local/lib -o "AudioPlayer"  ./src/Circle.o ./src/Screen.o ./src/main.o   -lSDL2
Undefined symbols for architecture x86_64:
  "_alGenBuffers", referenced from:
      _main in main.o
  "_alGenSources", referenced from:
      _main in main.o
  "_alGetError", referenced from:
      _main in main.o
  "_alcCreateContext", referenced from:
      _main in main.o
  "_alcMakeContextCurrent", referenced from:
      _main in main.o
  "_alcOpenDevice", referenced from:
      _main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [AudioPlayer] Error 1
19:25:39 Build Finished (took 2s.492ms)

我不太会理解这句话的意思。我成功编译并链接了SDL2。我不认为警告会导致这种情况,所以什么可能导致这个ld: symbol(s) not found for architecture x86_64错误?

[EDIT]我不认为我必须在Eclipse设置中链接任何东西。这是我的/usr/local/lib

中当前的内容

我不太了解OpenAL和Mac上的编译,但如果它说symbol(s) not found,我认为你需要为x86_64库添加一个包含路径到g++搜索。如果你能告诉我们/usr/local/lib里面有什么,那就太有帮助了。

刚刚看到你的编辑,我没有看到任何与OpenAL相关的东西,你确定已经安装了吗?也许它在另一个文件夹,但你必须包含它。库文件通常结束在。a或。so…我发现了一些可能有用的东西:StackOverflow情况类似。试试第三条评论。如果可能的话,将这些行放在g++选项中。您可能需要编辑构建过程。您必须编辑Makefile,这是最简单的方法。(我认为有一个Makefile,我也是新的)