title: C++ undefined reference to library functions
body: <p>I have a "small" graphics library I'm building, and I'm running into this error when attempting to build a test binary that links against it:</p>
  
  <pre><code>al_test.o: In function `test_wave()':
  al_test.cpp:(.text+0x1a7): undefined reference to `min::wave::wave(std::__cxx11::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; const&amp;)'
  ...
  </code></pre>
  
  <p>(and other, similar errors, but we'll focus on this one). The library is built in a makefile with the following rules:</p>
  
  <pre><code>all: libmgl.a libmgl.so
  
  libmgl.so: $(OBJECTS)
      $(LD) $* $(LDFLAGS) -shared -o $@
  
  libmgl.a: $(OBJECTS)
      $(AR) $(ARFLAGS) libmgl.a $^
  
  %.o: %.cpp
      $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) -c -o $@ $&lt;
  </code></pre>
  
  <p><code>CXXFLAGS</code> contains a few things, but most importantly <code>-std=c++14 -O3 -Wall -Werror</code> and all of the objects compile just fine and the static and dynamic libraries are output without error or warning.</p>
  
  <p>Now I have a file <code>source/test/al_test.cpp</code> meant to test <em>only</em> the audio portions of the library that looks something like this:</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include "twave.h"
  int main()
  {
      try
      {
          bool out = true;
          out = out &amp;&amp; test_wave();
          // out = out &amp;&amp; test_ogg();
          // out = out &amp;&amp; test_sound_buffer();
          if (out)
          {
              std::cout &lt;&lt; "Sound tests passed!" &lt;&lt; std::endl;
              return 0;
          }
      }
      catch (std::exception &amp;ex)
      {
          std::cout &lt;&lt; ex.what() &lt;&lt; std::endl;
      }
  
      std::cout &lt;&lt; "Sound tests failed!" &lt;&lt; std::endl;
      return -1;
  }
  </code></pre>
  
  <p>and the function <code>test_wave</code> is defined in <code>twave.h</code> like this:</p>
  
  <pre><code>#include &lt;stdexcept&gt;
  #include "min/wave.h"
  bool test_wave()
  {
      bool out = true;
  
      // Load invention wav file
      {
          const min::wave sound = min::wave("data/sound/invention_no_1.wav");
  
          // File should not be mono
          out = out &amp;&amp; !sound.is_mono();
          if (!out)
          {
              throw std::runtime_error("Failed wave file not is_mono");
          }
  
          // Other checks that aren't important...
      }
  
      return out;
  }
  </code></pre>
  
  <p>So here's my problem: <code>min::wave::wave()</code> definitely exists and definitely ought to be in the library. Here's a stripped-down <code>min/wave.h</code>:</p>
  
  <pre><code>#ifndef __WAVE__
  #define __WAVE__
  #include &lt;string&gt;
  namespace min {
  class wave
  {
    private:
      void load(const std::string);
    public:
      wave(const std::string&amp;);
  };
  }
  #endif
  </code></pre>
  
  <p>and <code>min/wave.cpp</code></p>
  
  <pre><code>#include "wave.h"
  
  min::wave::wave(const std::string &amp;file)
  {
      load(file);
  }
  
  // Definition of `load` omitted; I don't think it's important,
  // but know that it is here
  </code></pre>
  
  <p>So the file exists, the function declaration and definition both exist, and I can see in my <code>make</code> output that <code>wave.o</code> is being built and linked/archived into <code>libmgl.a</code>/<code>libmgl.so</code>. Yet the compiler claims it doesn't exist. It doesn't seem to be a link order problem; here's my process for building the tests:</p>
  
  <pre><code>g++ -c -Imin/ al_test.cpp -o al_test.o
  g++ al_test.o -L. -lmgl -lX11 -lGL -lfreetype -lopenal -lvorbisfile -o bin/al_test
  </code></pre>
  
  <p><code>mgl</code> is obviously the name of my library, and those are the other things on which it depends. I also tried replacing <code>-L.</code> with <code>-L/absolute/path/to/project/directory/</code>, to no avail.</p>
  
  <p>Why does g++ think my function is undefined?</p>
  
  <h2><code>nm</code> commands</h2>
  
  <p>By popular demand, here are a few <code>nm</code> commands and their outputs:</p>
  
  <p>the static library:</p>
  
  <pre><code>nm -C libmgl.a | grep wave
  wavefront.o
  wave.o:
  0000000000000090 T min::wave::load(std::__cxx11::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;)
  0000000000000000 W void min::wave::load&lt;min::mem_file&gt;(min::mem_file const&amp;)
  0000000000000000 W void min::wave::load&lt;std::vector&lt;unsigned char, std::allocator&lt;unsigned char&gt; &gt; &gt;(std::vector&lt;unsigned char, std::allocator&lt;unsigned char&gt; &gt; const&amp;)
  0000000000000000 T min::wave::clear()
  0000000000000880 T min::wave::wave(min::mem_file const&amp;)
  0000000000000720 T min::wave::wave(std::__cxx11::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; const&amp;)
  0000000000000880 T min::wave::wave(min::mem_file const&amp;)
  0000000000000720 T min::wave::wave(std::__cxx11::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; const&amp;)
  0000000000000080 T min::wave::get_sample_rate() const
  0000000000000060 T min::wave::get_data_samples() const
  0000000000000050 T min::wave::get_bits_per_sample() const
  0000000000000040 T min::wave::data() const
  0000000000000020 T min::wave::is_mono() const
  0000000000000030 T min::wave::is_stereo() const
  0000000000000550 T min::sound_buffer::add_wave_pcm(min::wave const&amp;)
                   U min::wave::get_sample_rate() const
                   U min::wave::get_bits_per_sample() const
                   U min::wave::data() const
                   U min::wave::is_stereo() const
  </code></pre>
  
  <p>...the dynamic library:</p>
  
  <pre><code>nm -C libmgl.so
  0000000000201020 B __bss_start
  0000000000201020 b completed.7631
                   w __cxa_finalize
  0000000000000460 t deregister_tm_clones
  00000000000004f0 t __do_global_dtors_aux
  0000000000200e88 t __do_global_dtors_aux_fini_array_entry
  0000000000201018 d __dso_handle
  0000000000200e90 d _DYNAMIC
  0000000000201020 D _edata
  0000000000201028 B _end
  000000000000053c T _fini
  0000000000000530 t frame_dummy
  0000000000200e80 t __frame_dummy_init_array_entry
  0000000000000548 r __FRAME_END__
  0000000000201000 d _GLOBAL_OFFSET_TABLE_
                   w __gmon_start__
  0000000000000420 T _init
                   w _ITM_deregisterTMCloneTable
                   w _ITM_registerTMCloneTable
  00000000000004a0 t register_tm_clones
  0000000000201020 d __TMC_END__
  </code></pre>
  
  <p>...and the test file:</p>
  
  <pre><code>nm -C al_test.o
                   U __cxa_allocate_exception
                   U __cxa_atexit
                   U __cxa_begin_catch
                   U __cxa_end_catch
                   U __cxa_free_exception
                   U __cxa_throw
                   U __dso_handle
  00000000000000e0 t _GLOBAL__sub_I__Z9test_wavev
                   U __gxx_personality_v0
  0000000000000000 r .LC1
  0000000000000000 T main
                   U __stack_chk_fail
                   U _Unwind_Resume
  0000000000000000 T test_wave()
                   U operator delete(void*)
                   U min::wave::wave(std::__cxx11::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; const&amp;)
                   U min::wave::is_mono() const
                   U std::runtime_error::runtime_error(char const*)
                   U std::runtime_error::~runtime_error()
                   U std::__cxx11::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;::_M_create(unsigned long&amp;, unsigned long)
                   U std::ios_base::Init::Init()
                   U std::ios_base::Init::~Init()
                   U std::basic_ios&lt;char, std::char_traits&lt;char&gt; &gt;::clear(std::_Ios_Iostate)
                   U std::basic_ostream&lt;char, std::char_traits&lt;char&gt; &gt;&amp; std::__ostream_insert&lt;char, std::char_traits&lt;char&gt; &gt;(std::basic_ostream&lt;char, std::char_traits&lt;char&gt; &gt;&amp;, char const*, long)
                   U std::cout
                   U std::basic_ostream&lt;char, std::char_traits&lt;char&gt; &gt;&amp; std::endl&lt;char, std::char_traits&lt;char&gt; &gt;(std::basic_ostream&lt;char, std::char_traits&lt;char&gt; &gt;&amp;)
  0000000000000000 b std::__ioinit
                   U typeinfo for std::runtime_error
                   U typeinfo for std::exception
  </code></pre>