dmd icon indicating copy to clipboard operation
dmd copied to clipboard

Add `pragma(libLocal)` to refer to local libs

Open ryuukk opened this issue 2 years ago • 35 comments

This adds a way to make packages depend on locally distributed libraries

Let's say a user manage a library A, he doesn't depend on dub, and he consume a static library that he put next to his module

If his users wants to use his library, they'll have to manually hunt the file that does the pragma(lib) and change the path manually

This is because the linker searches for the lib relative to the folder dmd was invoked from

This can very quickly become annoying to handle when you manage multiple libraries, it makes build scripts complex for no benefits

Example:

..
├── app
│   ├── main.d
│   └── main.o
└── libs
    └── lib_a
        ├── bin
        │   └── lib.a
        └── package.d

lib_a:

module lib_a;

pragma(lib, "local:bin/lib.a");

extern(C) int lib_get_int(); 

lib.a lives next to the file, in the bin/ folder

app:

It lives in a completely different folder

import core.stdc.stdio;

import lib_a;

void main() {
    printf("%i\n", lib_get_int());
}

Put the libraries in your libs/ folder, add the import path, and you should be good to go

dmd -i -I../libs/ -run main.d

Before:

/usr/bin/ld: cannot find local:bin/lib.a: No such file or directory

After:

42

ryuukk avatar Jul 31 '23 00:07 ryuukk

Thanks for your pull request and interest in making D better, @ryuukk! We are looking forward to reviewing it, and you should be hearing from a maintainer soon. Please verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the coverage diff by visiting the details link of the codecov check)
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

Please see CONTRIBUTING.md for more information.


If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment.

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub run digger -- build "master + dmd#15479"

dlang-bot avatar Jul 31 '23 00:07 dlang-bot

I fixed the code style, and i added 2 tests, 1 runnable, and 1 fail-compilation

Questions:

  • I need it to build a static lib, is the script i added gonna run automatically?
  • Does the script needs to support all platforms? (bash ok?)

ryuukk avatar Jul 31 '23 14:07 ryuukk

Tests are failing, and i'm not sure why, running ./build.d unittest, says all is passing on my end

ryuukk avatar Jul 31 '23 15:07 ryuukk

Try in the compiler/test folder:

./run.d runnable/pr15479.d fail_compilation/pr15479.d

dkorpel avatar Jul 31 '23 15:07 dkorpel

Ok i managed to fix the tests, should be good now (hopefuly)

ryuukk avatar Jul 31 '23 17:07 ryuukk

I have no idea what i have done with git (i hate that freaking thing)

ryuukk avatar Aug 01 '23 15:08 ryuukk

What commands did you run?

I rebased and squashed your commits, so you could reset to your upstream branch if you want.

dkorpel avatar Aug 01 '23 16:08 dkorpel

What commands did you run?

I rebased and squashed your commits, so you could reset to your upstream branch if you want.

I don't remember what command i typed, it was complaining about a merge conflict and i tried to follow what the git command told me to do..

Thanks for fixing it for me!

ryuukk avatar Aug 01 '23 20:08 ryuukk

Prefixing files with a "local:" runs afoul of Windows file naming conventions. It would be better to have pragma(liblocal, "filename");

WalterBright avatar Aug 02 '23 19:08 WalterBright

It complains about the static lib, i have no idea how to provide static lib for testing purpose that satisfy all the targets..

Anyone have suggestion?

ryuukk avatar Aug 11 '23 01:08 ryuukk

Unfortunately, I can't think of a better way than to provide a platform independent script that actually builds the static lib and then compiles the required binaries. The good part is that you can use D to write this script.

RazvanN7 avatar Aug 14 '23 11:08 RazvanN7

Instead of making a complex test, since this PR doesn't change anything about libraries, only the path, maybe i could just check for the existence of the file instead?

Otherwise i don't know how to invoke dmd in the test to create a library

ryuukk avatar Jan 01 '24 12:01 ryuukk

What use case does this cover that passing -L-Lbin/ would not ?

Geod24 avatar Jan 01 '24 15:01 Geod24

What use case does this cover that passing -L-Lbin/ would not ?

It's described in the example and in the changelog entry, it is to be able to consume self contained D projects that has static libraries (example: raylib or glfw)

It is similar to pragma(lib) but relative to the module instead of the working directory

Projects that consume the library no longer need to specify a path, that's a pointless step

dmd -run game.d and the user no longer have to care about micro managing paths or learn complex build tools

 tree glfw/
glfw/
├── bin
│   ├── linux
│   │   └── libglfw3.a
│   └── windows
│       └── glfw3.lib
├── funcs.d
├── package.d
└── types.d

Odin support this, it has contributed to it's rise in popularity due to how easy it is to make bindings for C libraries, D is failing behind due to its clunkyness, this PR is an attempt at fixing that

https://github.com/odin-lang/Odin/blob/master/vendor/raylib/raylib.odin#L98C1-L174

I think @schveiguy will appreciate it a lot for his raylib-d project, no longer have to hunt for dlls, cross compile them just once and put them in your folder and you are done

ryuukk avatar Jan 01 '24 17:01 ryuukk

Not a user of pragma(lib) myself so I might be missing something obvious here, but do pragma("lib", __FILE_FULL_PATH__.dirName.buildPath("bin", "linux", "library.a")) achieve the same thing as pragma("libLocal", "bin/linux/library.a") ?

Geod24 avatar Jan 02 '24 01:01 Geod24

Do you not notice the difference between what you suggest and what i suggest?

I will change language before i have to type:

import std.path;
pragma("lib", __FILE_FULL_PATH__.dirName.buildPath("bin", "linux", "library.a"))

ryuukk avatar Jan 02 '24 09:01 ryuukk

I will change language before i have to type: [...]

That's how you get a bloated language. If there is a reasonable way (and this is very reasonable) to achieve something currently, and there isn't a high demand for it such that it would make most users' life better, I don't think this is a good improvement.

Note that you may write a function to simplify the API, such as:

// This goes in your utility module
string localLib (Paths...)(string ffp = __FILE_FULL_PATH__) {
    import std.path;
    return ffp.dirName.buildPath(Paths);
}

// Use like this:
pragma(lib, localLib!("bin", "linux", "library.a"));

Geod24 avatar Jan 02 '24 10:01 Geod24

I will change language before i have to type: [...]

That's how you get a bloated language. If there is a reasonable way (and this is very reasonable) to achieve something currently, and there isn't a high demand for it such that it would make most users' life better, I don't think this is a good improvement.

Note that you may write a function to simplify the API, such as:

// This goes in your utility module
string localLib (Paths...)(string ffp = __FILE_FULL_PATH__) {
    import std.path;
    return ffp.dirName.buildPath(Paths);
}

// Use like this:
pragma(lib, localLib!("bin", "linux", "library.a"));

This solution is even worse, involves both

  • template
  • import a module
  • require phobos

My solution is basically free for the compiler, works without having a runtime, and makes the UX for the user much better, greatly simplifying their builds

Again, take a look at how other languages have solved this issue instead of expecting the user to write ugly code

and there isn't a high demand for it such that it would make most users' life better, I don't think this is a good improvement.

of course, other people are busy writing libraries for other languages

ryuukk avatar Jan 02 '24 13:01 ryuukk

My solution is basically free for the compiler, works without having a runtime, and makes the UX for the user much better, greatly simplifying their builds

No, it's not free for the language. It's a new pragma, a new way to do something, and what is added is hard to remove, hence why there needs to be a high bar for adding things.

You can do the above without a runtime as well - it's not that hard to write the code for it.

Geod24 avatar Jan 02 '24 14:01 Geod24

My initial PR was to enable

pragma(lib, "local:bin/linux/lib.a")

I got recomanded to add a pragma instead, wich is the right way to do

Wich is yet again, an evidence that you just disagree to disagree, disregarding the improvements it makes while suggesting me to instead write stupid code just to import a lib

ryuukk avatar Jan 02 '24 16:01 ryuukk

No, it's not free for the language. It's a new pragma, a new way to do something, and what is added is hard to remove, hence why there needs to be a high bar for adding things.

Yet every D compiler can have own pragma directives...

dejlek avatar Jan 02 '24 17:01 dejlek

Wich is yet again, an evidence that you just disagree to disagree,

Don't assume someone who disagrees acts in bad faith.

disregarding the improvements it makes while suggesting me to instead write stupid code just to import a lib

It's easy to argue for the benefits of a new feature while ignoring simplicity. This post explains why: https://alexgaynor.net/2020/nov/30/why-software-ends-up-complex/

Any new feature requires rationale strong enough to support its weight. When 50 lines of code in the compiler can be replaced with 5 lines in the library, that heavily detracts from the value.

take a look at how other languages have solved this issue instead of expecting the user to write ugly code

This is something you should provide. The only similar feature I know of is C's #pragma comment(lib, "x.lib"), and they don't have libLocal as far as I'm aware.

dkorpel avatar Jan 02 '24 18:01 dkorpel

This is something you should provide. The only similar feature I know of is C's #pragma comment(lib, "x.lib"), and they don't have libLocal as far as I'm aware.

C was designed many decades ago, and is currently held back by a committee of people, just like D ;)

Use case of this PR is already explained in the example above

I didn't want to provide "lang X has it therefore D should have it" argument, you would have complained about it i'm sure, instead i used my very own use case, something that is annoying me in my current project

Telling me to write suggested function and imports in phobos instead is both counter productive, off topic and also insulting, specially when it's coming from people who don't care when they write bunch of code that double compile time overnight and telling people who complain: "wontfix" https://github.com/dlang/dub/issues/2600

I sent this PR on Jul 31, 2023, only to get told to type this stupid code instead

Any new feature requires rationale strong enough to support its weight. When 50 lines of code in the compiler can be replaced with 5 lines in the library, that heavily detracts from the value.

disingenuous, barely ~20, and could be condensed to even less, you counted comments and brackets

not only you chose to also just disagree to disagree, but you also refuse to understand this PR, you disregarded my use case and problem

your argument is: "C doesn't have it therefore D shouldn't"

ryuukk avatar Jan 02 '24 19:01 ryuukk

I didn't want to provide "lang X has it therefore D should have it" argument, you would have complained about it i'm sure, instead i used my very own use case, something that is annoying me in my current project

your argument is: "C doesn't have it therefore D shouldn't"

Not at all, I was going by your quote:

take a look at how other languages have solved this issue instead of expecting the user to write ugly code.

This reads to me as "other languages have a non-ugly solution for this, so D should too". I asked you to elaborate on this because I'm not aware of such languages (giving C as a negative example, but still inviting you to give a positive example).

But if it's all a misunderstanding, then let's ignore this point.

dkorpel avatar Jan 02 '24 19:01 dkorpel

not only you chose to also just disagree to disagree, but you also refuse to understand this PR, you disregarded my use case and problem

I'm trying to steer this conversation to a productive discussion, but if that's how you interpret my comment, I don't know what to say to make your stance less hostile.

I guess I should just ask Walter and Atila to give this a yay or nay, and then we'll just leave it at that.

dkorpel avatar Jan 02 '24 20:01 dkorpel

Why Atila? he never show up to any PR / discussions, when asked about allocators progress he vanishes for 1 year to say hi

Walter already reviewed the PR saying it needs to be a pragma

Currently waiting for suggestions regarding what to do with the tests, maybe this needs another 6 months of waiting?

ryuukk avatar Jan 02 '24 21:01 ryuukk

@ryuukk I am sensitive to your argument that convenience is a big deal. You do a lot more library work than I, so you are more in tune with what works for libraries.

@Geod24 @dkorpel I'm glad you guys are looking out for unnecessary features that can be duplicated with existing constructs.

There's another aspect. This is a pragma feature, and it's my experience that adding more pragmas (for whatever reason) do not seem to contribute to the cognitive load of the language. It's why D has pragma, it's just a receptacle for more niche convenience features we don't want to bloat up the core language with. It's like the garage where you put stuff you don't want in the living room.

The implementation is also pretty self-contained and compact, and doesn't impact the rest of the compiler guts.

It's about 60-40 in favor of the proposal. @ryuukk please implement the detail suggestions, and I'll approve it.

WalterBright avatar Jan 03 '24 02:01 WalterBright

There's another aspect. This is a pragma feature, and it's my experience that adding more pragmas (for whatever reason) do not seem to contribute to the cognitive load of the language. It's why D has pragma, it's just a receptacle for more niche convenience features we don't want to bloat up the core language with. It's like the garage where you put stuff you don't want in the living room.

Finally someone who gets it...

dejlek avatar Jan 03 '24 18:01 dejlek

ping @ryuukk

WalterBright avatar Jan 05 '24 20:01 WalterBright

Sorry i got distracted with a git issue i had with my PR for dcd

I'll try to implement the requests

I also wanted to apologies for my tone above, it wasn't needed, and thanks for being patient with me

ryuukk avatar Jan 08 '24 22:01 ryuukk