Arduino-Makefile icon indicating copy to clipboard operation
Arduino-Makefile copied to clipboard

Local libraries in sketch directory

Open ladislas opened this issue 9 years ago • 13 comments

Hi guys!

I've made some test. It seems that if I put my .h and .cpp files in my sketch folder, it compiles, but if I put them inside a lib directory inside the sketch folder, it does not work...

So this works:

.
├── Blink.ino
├── Makefile
├── MyFirstLib.cpp
└── MyFirstLib.h

But this does not:

.
├── Blink.ino
├── Makefile
└── lib
    ├── MyFirstLib.cpp
    └── MyFirstLib.h

It this normal? :)

ladislas avatar Sep 01 '14 14:09 ladislas

yes that's normal and seems to be fixed by my PR #245 which you said you'd test :-)

sej7278 avatar Sep 01 '14 14:09 sej7278

I tried with your PR and I get the following error in the second example I described:

undefined reference to `MyFirstClass::MyFirstClass()'

ladislas avatar Sep 01 '14 17:09 ladislas

actually my USER_LIB_PATH is defined to something else.

the fact that it's not working doesn't surprise me. But I'm wondering if it could be useful to automatically look for libs inside the sketch directory. I often find myself putting code inside another lib directory inside my sketch directories for local code.

But maybe it's juste me and in this case it is not useful :)

ladislas avatar Sep 01 '14 18:09 ladislas

well USER_LIB_PATH should not be defined as one thing and your libraries stored elsewhere really.

could you maybe confirm it works if your libs are in your USER_LIB_PATH, then we could probably merge #245 and keep this open as a feature request, although your last comment seems to contradict your first one! ;-)

sej7278 avatar Sep 01 '14 21:09 sej7278

I confirm that it works when my libs are in my USER_LIB_PATH :)

and we can keep this as a feature request.

ladislas avatar Sep 02 '14 05:09 ladislas

in your first comment you say that if you put the library files in the same directory (1) as your sketch it works, but if you put them in a subdirectory (2) that's different to $(USER_LIB_PATH) it doesn't?

Exactly. I've tested (1) and (2) with the Blink example in the vanilla Arduino-Makefile. I've written a little lib to test this, you can find it here.

Case (1)

In case (1), I have the following:

tree structure

.
├── Blink.ino
├── Makefile
├── MyFirstLib.cpp
└── MyFirstLib.h

Blink.ino

#include "MyFirstLib.h"

MyFirstClass object;

void setup() {

    pinMode(13, OUTPUT);
    Serial.begin(115200);
}

void loop() {
    digitalWrite(13, HIGH);
    object.methodNumberOne();
    delay(1000);

    digitalWrite(13, LOW);
    object.methodNumberTwo();
    delay(1000);
}

Makefile

BOARD_TAG    = uno
ARDUINO_LIBS =

include ../../Arduino.mk

Conclusion

This compiles and works on an Arduino Uno

Case (2)

In case (2), I have the following:

tree structure

.
├── Blink.ino
├── Makefile
└── lib
    ├── MyFirstLib.cpp
    └── MyFirstLib.h

Blink.ino

#include "lib/MyFirstLib.h"

MyFirstClass object;

void setup() {

    pinMode(13, OUTPUT);
    Serial.begin(115200);
}

void loop() {
    digitalWrite(13, HIGH);
    object.methodNumberOne();
    delay(1000);

    digitalWrite(13, LOW);
    object.methodNumberTwo();
    delay(1000);
}

Makefile

BOARD_TAG    = uno
ARDUINO_LIBS =

include ../../Arduino.mk

Conclusion

This does not compile, I get the following error:

/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-gcc -mmcu=atmega328p -Wl,--gc-sections -Os -o build-uno/Blink.elf build-uno/Blink.o build-uno/libcore.a  -lc -lm
build-uno/Blink.o: In function `global constructors keyed to object':
Blink.ino:(.text._GLOBAL__I_object+0x4): undefined reference to `MyFirstClass::MyFirstClass()'
build-uno/Blink.o: In function `loop':
Blink.ino:(.text.loop+0x12): undefined reference to `MyFirstClass::methodNumberOne() const'
Blink.ino:(.text.loop+0x2c): undefined reference to `MyFirstClass::methodNumberTwo() const'
make: *** [build-uno/Blink.elf] Error 1

Other cases based on case (2)

If I set USER_LIB_PATH = $(realpath ./lib) and #include "lib/MyFirstLib.h", it does not work and I get the same error.

If I set USER_LIB_PATH = $(realpath ./lib) and #include "MyFirstLib.h" as I would normally do, it does not work and I get the same error.

But if I set USER_LIB_PATH = $(realpath ./lib) and I move the library's .h and .cpp inside a folder of the same name, i.e. ./lib/MyFirstLib, it does work:

.
├── Blink.ino
├── Makefile
└── lib
    └── MyFirstLib
        ├── MyFirstLib.cpp
        └── MyFirstLib.h

Conclusion

What do you think of that? Was I clear? :) I can make more tests if you want.

ladislas avatar Sep 02 '14 14:09 ladislas

@sej7278 no I haven't tried setting ARDUINO_LIBS but I'd like to do it without that as in a real project I may have a lot of different libs.

As for relative vs absolute path, i don't want my devs to change every include to make it work on their machine. It would be easier for everyone to just clone my computer and use the same username :) (kidding)

it's not urgent, take your time. and may be the Makefile is just not intended to be used this way.

ladislas avatar Sep 02 '14 15:09 ladislas

I will try it then :)

ladislas avatar Sep 02 '14 15:09 ladislas

ahhhhh! i've got it now. you're saying you want to put library headers/source inside the lib/ directory instead of lib/MyFirstLib/

i don't think that's even good c/c++ is it - what if two libraries have headers with the same name? certainly wouldn't be supported by the ide which moans if your sketch filename doesn't match the directory name.

sej7278 avatar Sep 02 '14 17:09 sej7278

yep that's the idea.

I have my main libraries such as Motors, Leds, Sensors, and stuff inside USER_LIB_PATH. Then, on a per sketch basis, I like to write Behaviors (a .h and a .cpp) that I'd like to put inside a folder inside my sketch folder.

You might be right, putting everything into a single folder might not be a good idea, so I'm willing to have something like lib/MyFirstLib :)

So the feature request would be to automatically look for files to include inside the sketch directory. But if it's too complex, I'll do otherwise.

ladislas avatar Sep 03 '14 07:09 ladislas

I agree with you, but it seems to work. have you tried it yourself?

ladislas avatar Sep 03 '14 09:09 ladislas

it seems only pde/ino files are checked for only a single file, cpp files are missed out of the checks from around line 709-744

could you try with this simple patch. it seems to work for a very basic test case of including a header file and reading a constant from it (not sure how to make a test case with a .cpp file that isn't a library, that's just weird c++):

Blink.ino:

#include "includes/myheader.h"

Directory structure:

Blink.ino
Makefile
includes/
   myheader.h

Patch:

diff --git a/Arduino.mk b/Arduino.mk
index c1981d0..85b5a8d 100644
--- a/Arduino.mk
+++ b/Arduino.mk
@@ -774,6 +774,8 @@ ifndef ARDUINO_LIBS
         $(shell sed -ne "s/^ *\# *include *[<\"]\(.*\)\.h[>\"]/\1/p" $(LOCAL_SRCS)))
     ARDUINO_LIBS += $(filter $(notdir $(wildcard $(USER_LIB_PATH)/*)), \
         $(shell sed -ne "s/^ *\# *include *[<\"]\(.*\)\.h[>\"]/\1/p" $(LOCAL_SRCS)))
+    ARDUINO_LIBS += $(filter $(notdir $(wildcard includes/*)), \
+        $(shell sed -ne "s/^ *\# *include *[<\"]\(.*\)\.h[>\"]/\1/p" $(LOCAL_SRCS)))
 endif

 ########################################################################

sej7278 avatar Sep 03 '14 09:09 sej7278

it works with the header but not with the MyFirstLib.

ladislas avatar Sep 03 '14 10:09 ladislas