How to Build and Compile WiringPi with JUCE?


#1

Hey I’ve successfully built and compiled JUCE on a raspberry pi b+ which works smooth. Now im trying to use WiringPi within JUCE with a knob/rotary encoder to display text on a lcd. Everything works but when I try to call wiringPi functions inside my juce app I get “undefined reference errors” to wiringPi. I guess my question is, how do I build WiringPi and Juce at the same time so that i can call wiringPi methods/functions inside of JUCE. Below is a snippet of my code

            Here is the error im getting below
        Source/SynthUsingMidiInputTutorial_01.h:114: undefined reference to `wiringPiSetup'
        Source/rotary_encoder.h:40: undefined reference to `digitalRead'
        Source/SynthUsingMidiInputTutorial_01.h:122: undefined reference to `pinMode'
        Source/SynthUsingMidiInputTutorial_01.h:125: undefined reference to `pullUpDnControl'


         ------------CODE SNIPPET------------------

              #include "rotary_encoder.h"
              //SynthUsingMidiInputTutorial_01.h
            class SynthAudioSource   : public AudioSource
            {
                 public:
                    SynthAudioSource (MidiKeyboardState& keyState)
                           : keyboardState (keyState)
               {
                   // add voices to our sampler
                   for (int i = 0; i < MAX_VOICES; i++)
                     {
                          synth.addVoice(new SamplerVoice());
                     }
                 // set up our AudioFormatManager class as detailed in the API docs
                  audioFormatManager.registerBasicFormats();
// now that we have our manager, lets read a simple file so we can pass it to our SamplerSound object.
                  File* file1 = new File("bass.wav");
                 ScopedPointer<AudioFormatReader> reader1 = audioFormatManager.createReaderFor(*file1);
                 File* file2 = new File("lead.wav");
                 ScopedPointer<AudioFormatReader> reader2 = audioFormatManager.createReaderFor(*file2);
                 File* file3 = new File("organ.wav");
                 ScopedPointer<AudioFormatReader> reader3 = audioFormatManager.createReaderFor(*file3);
                 BigInteger notes;

                 notes.setRange (0, 1, true);
                 SamplerSound::Ptr sound1 = new SamplerSound ("xx1", *reader1, notes, 0, 0.0, 1.0, 10.0);
                 synth.addSound (sound1);
                 BigInteger notes2;
                 notes2.setRange (1, 1, true);
                 SamplerSound::Ptr sound2 = new SamplerSound ("xx2", *reader2, notes2, 0, 0.0, 1.0, 10.0);

                 synth.addSound (sound2);
                BigInteger notes3;
                notes3.setRange (2, 1, true);
                SamplerSound::Ptr sound3 = new SamplerSound ("xx3", *reader3, notes3, 0, 0.0, 1.0, 10.0);

                 synth.addSound (sound3);
               int lcd;                //Handle for LCD
               wiringPiSetup();        //Initialise WiringPi
//Initialise LCD(int rows, int cols, int bits, int rs, int enable, int d0, int d1, int d2, int d3, int d4, int d5, int d6, int d7)
              if (lcd = lcdInit (2, 16,4, LCD_RS, LCD_E ,LCD_D4 , LCD_D5, LCD_D6,LCD_D7,0,0,0,0))
                {
                   std::cout << "LcdInit failed!:";
                 }

               pinMode(SwitchPin, INPUT);
               pinMode(RotateAPin, INPUT);
               pinMode(RotateBPin, INPUT);
               pullUpDnControl(SwitchPin, PUD_UP);

                    if (wiringPiISR(SwitchPin, INT_EDGE_FALLING, &btnISR) < 0) 
                   {
                      //cout << "Unable to init ISR" << endl;
                       }
                int tmp = 0;
               while (1) 
                {
                        rotaryDeal();
	           if (tmp != globalCounter) 
	     {
	          tmp = globalCounter;
	         if(globalCounter >= 10)
	             	    break;
	       }	
                  }
            // lcdClear(lcd);
             lcdPosition(lcd,0,0);           //Position cursor on the first line in the first column
            lcdPuts(lcd, "Lead Bass:");  //Print the text on the LCD at the current cursor postion

           }


               #include <wiringPi>
              //rotary_encoder.h
          static volatile int globalCounter = 0;
          unsigned char flag;
          unsigned char Last_RoB_Status;
          unsigned char Current_RoB_Status;

         void btnISR(void) 
                {
                  globalCounter = 0;
               }
        void rotaryDeal() 
             {
             Last_RoB_Status = digitalRead(RotateBPin);
             while (!digitalRead(RotateAPin))
                {
                 Current_RoB_Status = digitalRead(RotateBPin);
                   flag = 1;
                 }
                  if (flag == 1)
                 {
                  flag = 0;
                   if ((Last_RoB_Status == 0) && (Current_RoB_Status == 1)) 
              {
                  globalCounter++;
                }
                  if ((Last_RoB_Status == 1) && (Current_RoB_Status == 0)) {
                    globalCounter--;
               }
          }
      }

#2

Haven’t used WiringPi so far, but reading this example the instructions for compiling say you should call this

gcc -Wall -o blink blink.c -lwiringPi

The -lwiringPi argument instructs the linker to link the executable compiled from the blink.c source code with the precompiled library with the name wiringPi, this means every call to a wiringPi function should be taken from there. From what you describe it seems you have missed to link your application to wiringPi. To do so open your project in the Projucer go to Exporter/Linux Makefile (assuming you are building your raspberry Pi project through a simple makefile exporter) and find the field “External Libraries to Link”. There put in wiringPi, this will lead the application to be linked with the -lwiringPi option in the build process.

Of course you need to have built the wiringPi library once (or have downloaded it as prebuilt packet) before you can link against it, but that is needed even for the example project, so I think this should already have happened and won’t be your problem here…

Note that I haven’t tested anything of this at all. Just trying to explain what you generally need to do if you want to use external libraries


#3

I’ve done exactly both those - I needed extra compiler flags -L/usr/lib/arm-linux-gnueabihf and External Libraries to link wiringPi (& wiringPiDev) but it was a while ago


#4

@Dub and @PluginPenguin For some reason im still getting those undefined errors. Heres what im doing…

In Projucer I have the following:
Extra Library Search Paths = /home/pi/wiringPi
Extra Compiler Flags = L/usr/lib/arm-linux-gnueabihf
External Libraries to Link = wiringPi

Then im runnng the following
midisynthdemo/SynthUsingMidiInputTutorial/Builds/LinuxMakefile $ make

and the following errors occur…

         Linking SynthUsingMidiInputTutorial
         build/intermediate/Debug/Main_90ebc5c2.o: In function 
         `SynthAudioSource::SynthAudioSource(juce::MidiKeyboardState&)':
          SynthUsingMidiInputTutorial_01.h:117: undefined reference to `lcdInit'

          SynthUsingMidiInputTutorial_01.h:161: undefined reference to `lcdPuts' 
          collect2: error: ld returned 1 exit status
          Makefile:76: recipe for target 'build/SynthUsingMidiInputTutorial' failed
          make: *** [build/SynthUsingMidiInputTutorial] Error 1

It seems as though the <lcd.h> header file is somehow not getting compiled or build for some odd reason… :frowning:


#5

Solved!!! - Ok I searched online for similar errors regarding wiringPI and lcd.h compile errors, and had to add these two libraries like below:

Extra Compiler Flags = -L/usr/local/lib -lwiringPiDev -lwiringPi
Extra Linker Flags = -L/usr/local/lib -lwiringPiDev -lwiringPi
External Libraries to link = wiringPi
Header Search Paths =
/home/pi/wiringPi/wiringPi
/home/pi/wiringPi/devLib

Extra Library Search Path = /home/pi/wiringPi

And everything worked!!


#6

Although I believe you this works, your solution looks a lot like the outcome of some try and error work and contains unneeded repetitions. As I believe that you like to learn why you do things and not just how to get it working without having a real knowledge of the sense behind your config I’ll try to go into detail a little bit. Let’s see what the values for the fields you specified mean:

If you look here you’ll see that the -L... flag specifies a search path for a library that is linked via -l.
If you look a bit later you write

Now, if you are filling a value in the Extra Library Search Path field, this will result in setting a -L flag when gcc is called by the makefile - So this entry will result in appending the flag -L/home/pi/wiringPi. So in fact, you are including one library search path (/usr/local/lib) via the -L field directly and another one (/home/pi/wiringPi) via the Extra Library Search Path field. There should be no reason to use such a mixture of styles in the same project because it is simply confusing.

Now the second thing is: Why do you think you need to add usr/local/lib to the library search path? I’m not 100% sure but I believe it will be on the library search path by default. Furthermore I don’t think that you’ll find wiringPi inside this folder. Most likely it will be located in the second folder you specify under Extra Library Search Pahts (/home/pi/wiringPi). So adding this path does not hurt but is most likely also not needed at all.

Third thing: Why did you see the need to pass the same library search path as compiler flags as well as linker flags? There is no real need for that. You link to wiringPiDev twice (through -lwiringPiDev as compiler flag as well as linker flag) and you link to wiringPi three times (through -lwiringPi as compiler flag as well as linker flag and as entry in the External libraries to link). No need for that, most likely you are getting no error because gcc simply ignores the redundant entries.

Try this:

External Libraries to link = 
    wiringPi
    wiringPiDev

Header Search Paths =
    /home/pi/wiringPi/wiringPi
    /home/pi/wiringPi/devLib

Extra Library Search Path = 
    /home/pi/wiringPi

Without having tested it, I’m sure this will have the exactly same effect but will show a lot better what you are really doing :wink:


#7

thanxx a bunch @PluginPenguin for your awesome advice. Still learning c++/compile on linux, and it is totally night any day from windows…


#8

I managed to get it working in a JUCE project with minimal setup…

Extra compiler flags: -lwiringPi
Extra linker flags: -lwiringPi
External libs to link: wiringPi

Then in the header file that uses the library:

#if defined(JUCE_LINUX) && defined(__arm__) // Assume we're on the Raspberry Pi
#define RASPBERRY_PI 1
extern "C" {
#include <wiringPi.h>
#include <mcp23008.h>
}

I think I just followed the build instructions from the wiringPI website and linked the library.