首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用OpenAL在Mac上编译x86_64会导致没有发现架构x86_64错误的符号。

使用OpenAL在Mac上编译x86_64会导致没有发现架构x86_64错误的符号。
EN

Stack Overflow用户
提问于 2016-11-15 00:31:26
回答 1查看 302关注 0票数 0

我对C++相当陌生,但我一直想制作一个带有音频的程序,我找到了OpenAL。作为参考,我使用Eclipse和运行OSX10.10的Mac。我找到了一个简单的教程程序:

代码语言:javascript
复制
#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, "Oops\n");
    return 1;
}
ctx = alcCreateContext(dev, NULL);
alcMakeContextCurrent(ctx);
if(!ctx)
{
    fprintf(stderr, "Oops2\n");
    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;
}

但是,当我试图编译这个程序时,我会得到一个错误。以下是编译过程:

代码语言:javascript
复制
    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 可能导致错误的原因是什么?

编辑--我不认为我必须链接到设置中的任何东西。是目前在我的/usr/local/lib

EN

回答 1

Stack Overflow用户

发布于 2016-11-15 00:35:58

我对OpenAL和在Mac上编译并不了解太多,但是如果它说的是symbol(s) not found,我认为您需要为x86_64库添加一个包含路径到g++搜索。如果您能够告诉我们/usr/local/lib中的内容,那将是非常有帮助的。

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40600172

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档