dmd
                                
                                 dmd copied to clipboard
                                
                                    dmd copied to clipboard
                            
                            
                            
                        Add `pragma(libLocal)` to refer to local libs
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
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:andReturns:)
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"
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?)
Tests are failing, and i'm not sure why, running ./build.d unittest, says all is passing on my end
Try in the compiler/test folder:
./run.d runnable/pr15479.d fail_compilation/pr15479.d
Ok i managed to fix the tests, should be good now (hopefuly)
I have no idea what i have done with git (i hate that freaking thing)
What commands did you run?
I rebased and squashed your commits, so you could reset to your upstream branch if you want.
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!
Prefixing files with a "local:" runs afoul of Windows file naming conventions. It would be better to have pragma(liblocal, "filename");
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?
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.
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
What use case does this cover that passing -L-Lbin/ would not ?
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
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") ?
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"))
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"));
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
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.
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
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...
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.
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"
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.
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.
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 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.
There's another aspect. This is a
pragmafeature, 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 haspragma, 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...
ping @ryuukk
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