On 4/13/18 7:00 PM, Jonathan Marler wrote:

@Steven You're just addressing the example I gave and not thinking of all the other ways version (or other compiler flags) could change things.  For example, you could have version code inside a template that changes mangling because it is no longer inferred to be pure/safe/whatever.


Yeah, but that results in a linker error. Your solution results in a linker error as well. Either way, you need to adjust your build. Trying to make the liner spit out a nice error is an exercise in futility.

The point is, this is a solvable problem.  All we need to do is save the compiler configuration (i.e. versions/special flags that affects compilation) used when compiling a library and use that information when we are interpreting the module's source as as an "pre-compiled import". Interpreting a module with a different version than was compiled can create any error you can possibly come up with and could manifest at any time (i.e. compile-time, link time, runtime).

consider:

int libraryFunction(int x)
{
    version(UseSpecializedMethod)
    {
       // do it the specialized way
       ...
    }
    else
    {
       // do it the slow way
       ...
    }
}

Do we need to penalize user code that doesn't define the library-special version UseSpecializedMethod? Making code not link because it didn't define library specific implementation details the same as the library isn't going to help.

The jist is that if we don't solve this, then it's up to the applications to use the same versions that were used to compile all their pre-compiled D libraries...and if they don't...all bets are off. They could run into any error at any time and the compiler/type system can't help them.

For versions, it only makes a difference if the versions affect the public API (and in a silent way). I'm fine with linker errors to diagnose these.

Note: it's really bad form to make a library who has public API changes when you define different versions. It's why I'm trying to eliminate all of those cases for version(unittest) from phobos.

For compiler features, if you get different symbols from the exact same code (in other words, ALL code involved is exactly the same), then it may be useful to embed such a compilation linker mechanism to give a somewhat better linker error. For example, with dip1000, if a library function using dip1000 adds an attribute that normally wouldn't be added, you could include such a symbol, and then the linker failure would show that symbol missing (and hopefully clue in the user).

But even this has drawbacks -- what if you never call that function? Now you are having a linker error where there normally wouldn't be.

But there are actually a couple real ways to solve this, and they aren't simple. One is to invent our own linker/object format that allows embedding the stuff we want. Then you don't import source, you import the object (this is similar to Java).

The second is to actually spit out a specialized import file that puts the right attributes/definitions on the public API (and should include any implementation that needs to be inlined or templated).

-Steve

Reply via email to