-
Notifications
You must be signed in to change notification settings - Fork 464
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC] Refactor/Finalize/Encapsulate C Interface #631
Comments
This is incredibly useful and was long overdue. The sass_interface file has never been really well documented. A few comments there would go a LONG way towards helping implementers. |
IMO there is still some place for improvement with the include paths :) |
I'm not so sure about the self-generating header declarations though. Some languages have FFI libraries that can parse header declarations but completely choke on non-trivial macros. |
I'm pretty sure there are other places (like ast.cpp) where more complex makros are used. |
Macros aren't problematic per se, just the ones in public headers. The public headers are usually the only thing parsed by FFI libraries, binding generators, etc. |
@QuLogic maybe you could clarify this for me. I guess I have to return a pointer from all the
|
Yea, that definition will return the union by value, which means the stuff from the structure needs to be copied from the function's copy to the caller's copy. That means the compiler needs to know the actual size of it. Using a pointer would reduce that copying to just the pointer (which may fit in a register even). You could do:
in the header and then just use |
I made some progress and was able to move all structs and other implementation details into sass.cpp, while only leaving functions that deal with pointers in sass.h. There are IMO some minor flaws with how the specific IMO I could change all setters/getters for Sass_Values to accept the generic value, instead of needing the fetch the specific struct first. But this may lead to crashes if people are passing it the wrong Sass_Value type. But the same applies to getters/setter for list values if you give it an index that is out of bound. So the question is if this is acceptable, as the user is able to check the length or type before calling the function? I could also add safe guards and do the checks everytime, but I do not like this idea!
I'm not yet sure if I should go for a typedef for Sass_Values. IMO it does not work to use the same name as @QuLogic suggested. I would probably need to create other names. But libsass seems to hide the pointer for |
That |
Re-added
There is no other place than |
I got everything ready for a PR in another local branch.
If the implementor does not use Will need to update the docs before doing the PR! Hope you guys like it! //CC @am11 Would you be willing to try to compile it against node-sass? |
@mgreter, great work refactoring interface! 👍 I will definitely give it a shot. Unfortunately, we don't have functions implemented yet. But rest of it can be absolutely tested out! :) |
I basically meant that it should still compile as before if you do not use functions or values in the binding! Would be interesting to know if this is really the case! Beside that feel free to try to adapt node-sass to use the new interface, but I'll add some more documentation once it is finished :) |
Wait, we have a generic Sass function callback? |
@mgreter, unfortunately, it is failing with GCC and VCC. For GCC errors, see https://travis-ci.org/am11/node-sass/jobs/40434617#L353-L510. For VCC see http://pastebin.com/zMrvajsv. |
Hmm, strange, will try on linux, as I can get this one running :) @hcatlin : Not sure what you mean by "generic", but yeah, there is the possibility to hook functions into libsass pretty easy via C. |
@mgreter I haven't had a chance to look at what you did, but just based on the log, it looks like you need to include a header to get @am11 Complete side note, but you shouldn't have to run |
@mgreter generic as in, it functions like method_missing and unresolved function call attempts during execution are passed to the callback dynamically. Aka, they don't have to be defined (named) at compile time, and we could write a full RubySass compatibility layer (you could write Sass functions in Ruby) |
The more limited (aka, must be predefined) function callback system was supposed to get ripped out and replaced with one that functions as a function resolver. |
@QuLogic I was thinking about the consts and to be honest I am not really sure where they make sense and where not. Maybe you could give some pointers I could fallow? @hcatlin It actually was ripped out with a refactoring about a year ago, I added them back (also about a year ago) since perl-libsass already supported them (and they are IMO quite usefull). But a more generic solution seems even better (I guess this could even co-exist). I may have a look and see how difficult it would be to add something (I already wanted to check if overloading imports etc. would be feasable). |
Here is one mysterious looking error from VCC:
Would it make sense to use |
@mgreter Well, in C, I don't think it's as necessary as C++. It makes no real difference for integral types, and there are no classes. It really only makes sense with pointers, e.g., The usual contract is |
@QuLogic I guess |
@am11 Got it compiled on linux, was just some header missing as @QuLogic pointed out correctly!
Just don't forget to add the new source file @QuLogic dropped most of the consts (only left the ones for char*)! |
For this one, |
I added the following includes to all C headers.
For the node-sass warning see here. |
Updated the documentation wiki page for a better overview! |
And added json error reporting for the new context API! //CC @am11 |
@hcatlin Regarding generic callback function: In my bindings I can now define a function named |
Next commit adds possibility to overload |
@QuLogic, thanks for the tip. Actually, I added couple of statements in .travis.yml to update g++ and gcc. I understand @mgreter, thanks! It built and passed both tests. https://travis-ci.org/am11/node-sass/builds/40448866. While on windows, it is still choking with handful of |
darrenkopp/sassc-win and darrenkopp/libsass-net stopped working. BTW, any thoughts on splitting sassc-win test code for Appveyor? Currently, we have to update submodule to run the test. |
To run the tests on node-sass, following is the sequence: # add remote and get fresh code
# git remote add node-sass https://github.com/sass/node-sass
git pull --rebase node-sass master
# install npm, fetches all the dependences and libsass prebuild binaries
npm install
# to build binaries manually and making sure that you are testing against
# latest binary (not the prebuild ones)
node scripts/build -f
# to run the test
npm test |
Definitely, overloads are one of the most requested features. This branch is crazy! Guessing we call this 3.1 ;) |
Thanks for all the feedback. If no one objects I'm going to create a PR now! @am11 For the errors in json, please see this commit here: I also tried to overload import, but that seems to be a bit more difficult as this is happening in parser, which does not seem to have access to env, where the custom functions are stored. Otherwise it would probably have been trivial to add import overloading! |
@mgreter, it is not exposed in |
Also, does it now capture |
You have to use the new API then (or you port that part back to sass_interface yourself). |
Using your API documentation, https://github.com/mgreter/libsass/wiki/API-Documentation, I will try to refactor node-sass' bindings with new API in a separate branch and wait for libsass to get a tagged release, before merging into node-sass. :) |
IMO we can/will keep the old |
Pull request has been placed: #635 Sorry to also include the other commits, but I'm too lazy right now to take them apart ... |
Hmm... I'm not really a fan of using a ton of functions just to set options on a struct. That's a lot of wasted overhead. I think a better approach would be to implement a single function that returns a sass_options struct initialized with sane defaults. Then you could modify that struct yourself to customize it. I don't really see myself switching to this new API, so perhaps keeping the old one around is a good idea. Sent from my iPhone
|
Also, there's really only a handful of implementors that are going to use this API, right? sassc, myself and maybe a few others. All the higher-level implementors are just going to call sassc, no? I think the old sass_interface API was fine, it just needed some solid documentation and comments to make sure folks used it correctly and avoided the common pitfalls. So creating a totally fail-safe API at the expense of performance (no matter how small the decline in performance) isn't a good deal in my opinion. Faster is better. Finally: I've only looked at the documentation on my iPhone on the road, so my apologies if I've missed something. Sent from my iPhone
|
Is it really? GLib and GTK+ did this for every structure they had, and they don't seem to be complaining.
There's no reason there couldn't be helper functions like this alongside the lower-level getter/setters.
No, absolutely not. Everyone (binding-wise) should use the API. Shelling out to |
The API is only used to setup the context and has no influence on the libsass compilation speed. |
@QuLogic Maybe you could explain why this leads to a more robust ABI? I _ guess_ I know why, but some clarification would be greatly appreciated (specially regarding libtool)! |
Fair enough. I'm fine with the getter/setters as long as I don't have to call all 15 of them just to set the options every time I compile a file. A helper that returns an option struct with initialized defaults would be perfect. As for performance: my general policy is to avoid things that degrade it if at all possible. I know that the additional function call overhead won't make a noticeable difference in speed, but over time, if more and more changes add a little extra overhead, it can add up! Sent from my iPhone
|
Yep, but setting up the context is part of running Libsass. I definitely understand that this isn't part of the actual compiling step, but it is still a step in the whole process and will be slightly slower than it used to be under the old API. So setting up Libsass will be slightly slower. (I'm also a performance nazi... I may be in the minority.) Sent from my iPhone
|
@mgreter Yes, good point, I was debating whether to mention that because it can be long to explain... Basically, it means the underlying implementation is uncoupled from the API. If downstream users have access to the structure fields, those fields must stay the same forever (or at least until you create a 4.0.0 or something, and explicitly notify people). Theoretically, if you wanted to add stuff, you couldn't, because a downstream user might be allocating the structure themselves, and when libsass code goes to access the new field, you get a segfault because the structure is not big enough. (I don't think that has stopped libsass developers before, but I chalk that up being more "beta" before. Now that many people use it, it's more important to avoid that.) Once the structure fields are hidden, all the downstream user has to worry about is a pointer. They can't accidentally allocate it too small, or forget to initialize a new field, or whatever... The libsass developers are free to change the underlying setup entirely, e.g., instead of a structure, it could actually just be a pointer to the C++ class. But downstream doesn't have to know or care. They stay happy as long as nothing's removed from the API, i.e., it gives you forward compatibility. |
My guess was, that if we add more stuff (functions) to the header and that library get installed over an old one in the system lib folder, software that was built against the old library (dynamically linked), will still work/link happily with the newly installed one. Correct? IMO this would also be true if we always added stuff the end end of the structs, but not if something got added in between ... |
You are correct, except in the case where someone allocates the structure themselves. Then the field you added may or may not be initialized. In fact, the structure may not even be big enough to contain the new fields. |
Good point with uninitialized structs because of wrong initialization. |
Thanks for all the Feedback! |
In reference to #79, sass/sassc#26
We are getting more false bug reports because people do not use the interface correctly. I guess this is mostly due to lack of documentation. Some parts of the API also feel pretty clumsy, as we have to set the same options for file_context and data_context separately.
Therefore I propose quite a radical refacor, which I already have tested in a local branch. This will mean that bindings will once again have to fallow suit, but I really hope this would be the last time! I also did that already for the
perl-libsass
bindings (took me about 1 hour, and the code now looks much cleaner and leaner).I have taken apart the c context structs into one more levels than before.
I have added a wiki page with documentation, in the hope it will add more value to this API refactoring.
Best regards
The text was updated successfully, but these errors were encountered: