If an identifier is defined in the current dart file, then that identifier shadows elements with the same identifier that are defined in other files included using the import directive. When using such an identifier in the current file, no errors occur, the version from the current file is used.
If some id is defined in file 1 and file 2, but is not defined in the current file, then an error will occur when trying to apply the identifier, which can be eliminated by using import prefixes or show, hide commands.
The logic described above is clear. But when working with the dart:core library, the following error may occur. Let's consider the cause of the error using the print function as an example.
If the print function is not defined in the current file and that function is defined in one of the import files, then the dart:core version of the library will be grayed out. No compilation errors that require an import prefix or the show/hide command will be generated.
The described situation can lead to confusion. The same applies to some other dart:core libraries. There are examples below.
// test2.dart
void print() {
}
// test.dart
import 'test2.dart';
void main() {
// some useful function from test2.dart
print2();
// static error due to inappropriate argument types,
// not due to collision with print function from dart:core
print('work is done');
}
This error persists when explicitly including the dart:core file.
In connection with what has been said, there are the following questions.
Will the dart developers read my message, or where do they need to forward it to read it?
Is this really a bug or was it meant to be? I propose to correct it so that the language is more simple and understandable.
I expected that if an identifier in one of the files matches an identifier from the dart:core library, the behavior will be the same as if a simple other package, file.
The rules for name conflicts are special for names coming from platform (dart:) libraries.
Normally if you import different declarations with the same name through two different imports, it's a conflict. You get an error if you try to refer to the name, because the compiler cannot figure out which one you mean.
However, if you import different declarations with the same name, and some, but not all, come from dart: libraries, then the declarations from the dart: libraries are ignored, and the non-platform libraries take precedence. (And if there is only one declaration from a non-dart: library, it just works as normal.)
The reason for this exception is that Dart libraries typically come from packages, where you can control which version of the library you get.
You won't get new declarations without doing a dart pub update or similar. That means that a new name conflict are only introduced at times where you are actively developing, and you can then handle.
Platform libraries come from the SDK, and your SDK can be updated independently of the packages you are working on. Even if you tested your application thoroughly and locked all your dependencies to specific version that you know will work, it might end up being run on a newer SDK.
Because of that, adding new declarations to the platform libraries was considered more dangerous than adding them to normal packages. To avoid it being practically impossible to add anything to the platform libraries, it was instead decided to not make such new conflicts into errors.
If the platform libraries introduce a new declaration, it should not affect your imports. It won't introduce a new conflict.
(It can cause other errors, because no API change in Dart is ever entirely safe, but at least it won't cause import conflicts.)
Related
BACKGROUND
I'm building an iOS app (which I'll just call MyApp from here) that will rely on calculations done by several separate static libraries (which I'll call Lib1, Lib2, Lib3,...). Each library is built in it's own project, then imported into a single workspace (so the workspace will contain MyApp, Lib1, Lib2, ...). More details on how this is set up here. The libraries are used by other products that are independent from MyApp, so I want to minimize any changes in the libraries. The libraries are also written in (plain) C, so there are no header files.
Certain function names are used by multiple libraries (so both Lib1 and Lib2 might each have a DoStuff method). Functions with the same name generally do the same thing, but there are some specifics about how that do it that can be different between libraries, so the actual code in DoStuff on Lib1 might be quite different than the code in DoStuff on Lib2. It would be very difficult to write one universal DoStuff that would be exactly the same in each library.
THE ISSUE
While the app is running, it isn't calling the correct DoStuff from the correct library. I found out about this because the wrong function was called during a debug session (which eventually caused the app to crash, due to the subtle differences in the DoStuff functions).
WHAT I'M LOOKING FOR
Each library has only one entry point from MyApp, and each entry point is uniquely named. If DoStuff is called from the entry point method of Lib1 (or any other method on Lib1, for that matter), then I want it to call the DoStuff method on Lib1. What's the best way to make that happen?
Is there any way (maybe through a setting somewhere in XCode) I can make it so that each library is it's own namespace? That would be my preferred way to fix the issue. I guess I could go through and rename the duplicate functions so that they are all unique (so the DoStuff method on Lib1 could be renamed to Lib1DoStuff, or something similar), but there are hundreds of functions that could have duplicate names, and we are going to be adding hundreds of libraries to the project, so having to go in and rename all the functions by hand and fix all the calls to them would take a significant amount of time, and my boss doesn't see that as a viable option.
UPDATE
After looking at the comments from Josh Caswell and some of the links he provided, it looks like it might be possible to automatically rename all the functions when the libraries are compiled, and that would be the best way to try to fix THE ISSUE above. From what I've seen, the objcopy that gets mentioned in a couple of the links in the comments isn't support on iOS. I eventually came across this blog entry, which talks about creating custom build rules for Xcode targets, and this blog that talks about custom build settings and build phases.
Am I right to assume that I can use scripts at some point in the build process to automatically append to the name of all the functions in each of my libraries, instead of doing it manually as I described in the last paragraph of the WHAT I'M LOOKING FOR section above? If so, which is the correct part of the build process to make those changes? Lastly, what would the syntax look like for doing something like that? The 'scripts' used in the different parts of the build processes certainly doesn't look like Obj-C. I've never used these 'scripts' before, so I'm completely in the dark on how I'd use them, and that's what I'm looking for help with.
I tried to be as clear as I could, but if there are any questions on what I'm asking please let me know.
Why isn't xcode calling the correct library function?
Let's say I have 3 C libraries as mentioned by you. Let's say it has the following code.
Library 1 - test1lib.a with code:
#include <stdio.h>
void doStuff()
{
printf("\nDoing stuff for lib1\n");
}
void uniqueEntryPoint1()
{
printf("\nUnique entry point for lib1\n");
doStuff();
}
Library 2 - test2lib.a with code:
#include <stdio.h>
void doStuff()
{
printf("\nDoing stuff for lib2\n");
}
void uniqueEntryPoint2()
{
printf("\nUnique entry point for lib2\n");
doStuff();
}
Library 3 - test3lib.a with code:
#include <stdio.h>
void doStuff()
{
printf("\nDoing stuff for lib3\n");
}
void uniqueEntryPoint3()
{
printf("\nUnique entry point for lib3\n");
doStuff();
}
Here each library has a unique function and one common function doStuff()
When we add these 3 libraries to xcode and link them. xcode links but does not load all the objects files. Let's say the objective C code is like this:
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
uniqueEntryPoint1();
}
The output is
Unique entry point for lib1
Doing stuff for lib1
In this case xcode will only load symbols which are referred (library 1 objects) in this case.
If you are read about linker flags/options such as -all_load, -force_load and -objC, you will have better understanding.
If we add -all_load linker option, it will force linker to load all the objects of libraries so we will get the following error in xcode
ld: 2 duplicate symbols for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
The reason this fails as the linker detects that doStuff() is redefined multiple times.
The only way around this problem is change the linker input i.e. symbols present in these 3 libraries. This is already mentioned by Josh in the comments. I will add my $0.02 to it.
Possible Solutions
Solution 1:
The best solution (self explanatory) is to change the source code if you have access to the same.
Solution 2:
Use objcopy to rename or prefix the function as provided in the answer of this How to deal with symbol collisions between statically linked libraries?
Now your doubt on how to find the objcopy.
Option 1:
You can use this project https://github.com/RodAtDISA/llvm-objcopy. This will be tricky to compile as it builds along with llvm. You will have to follow instructions at http://llvm.org/docs/GettingStarted.html and http://llvm.org/docs/CMake.html.
If you rewrite the https://github.com/RodAtDISA/llvm-objcopy/blob/master/llvm-objcopy.cpp, you can probably reuse the parsing and object rewriting logic without depending upon llvm.
Option 2:
Compile and reuse binutils objcopy from https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=binutils/objcopy.c;h=2636ab4bcb34cf1e1e54db9933018a805b366727;hb=HEAD
Solution 3:
You can follow the answer provided by Richard in this link Rewriting symbols in static iOS libraries. This is more of a hack but using a hex editor you can rewrite the symbols if their length is kept the same. If you have more symbols and its a big library, you can consider using https://sourceforge.net/projects/bbe-/ and nm to write a script.
All of this is a considerable effort but apparently there is no shortcut.
I'm currently playing with the Dart version of Angular 2.
I have seen that the library is using a lot of Metadata as #Component for example.
I would like to know how are those directives working?
I went on http://www.darlang.org. They explain how to define an annotation but not how to use it to construct an object as it is done in angular.io.
Could someone explain how the magic is working?
In Dart annotations by itself don't do anything than exist beside the code element where they are added.
At runtime:
You can use dart:mirrors to query the imported libraries for elements like fields, functions, classes, parameters, ... for these annotations.
dart:mirrors is discouraged for browser applications. In this case you can use the reflectable package with quite similar capabilities.
See also:
https://www.dartlang.org/articles/reflection-with-mirrors/
https://api.dartlang.org/1.14.1/dart-mirrors/dart-mirrors-library.html
https://stackoverflow.com/search?q=%5Bdart-mirrors%5D+annotations
At buildtime
You can create a transformer and register it in pubspec.yaml to be run by pub serve and pub build.
In this case the Dart analyzer can be utilized to query the source files for annotations and, like Angular does, modify the source code in a build step to add/replace/remove arbitrary code.
For more details about transformers
- https://www.dartlang.org/tools/pub/assets-and-transformers.html
- https://www.dartlang.org/tools/pub/transformers/
- https://www.dartlang.org/tools/pub/transformers/examples/
- https://www.dartlang.org/tools/pub/transformers/aggregate.html
- https://pub.dartlang.org/packages/code_transformers
Many of the samples I have seen for angular2 have the following import statement:
import {bind} from 'angular2/di';
I am working in VS Code (with TypeScript) and it complains about not being able to find the angular2/di module.
However I do see a bind function defined in angular2/angular2.d.ts. If I change the import statement to the following, then the error goes away.
import {bind} from 'angular2/angular2';
Is the question in the title off-base and I am making some erroneous assumption?
If not, why do many samples reference one module to import the bind function from, yet I seem to be able to get it from a different module?
Most likely because you looked at versions from older alphas. Look at the angular2.ts file. Everything is exported from it. Also note that the d.ts is going to contain everything to resolve types in your IDE and at compilation time. What import does is actually importing the .js files.
Something strange is going on with my Xcode 5. All of a sudden I'm getting Undeclared Identifier errors for all the values in my Constants.h file, which is imported in my Prefix.pch file.
Two things are weird here:
This hasn't happened before.
When I do build and run, the build succeeds and the app runs with no problems.
I tried restarting Xcode and the simulator, and even restarting the whole machine. No luck.
What's going on? How can I get rid of these false errors?
EDIT following rmaddy's request. The error is Use of undeclared identifier kOffsetFromTop (for example, there are other similar errors with different constants.)
I don't really want to post my entire constants file, but the constant in question is defined like this:
static int const kOffsetFromTop = 20;
When this happens I normally do the following
Comment out the import from the .pch
Clean all ⌘⌥⇧K
Delete derived data
Build
Then uncomment the import from the .pch and build again. I'm not sure which step is actually sorting the issue but this normally gets me going again.
Multiple points here :
You have a warning, not an error. A warning is just that, it warns you but does not prevent the code to compile. That is just to warning you that something is odd or unexpected, or to tell you that what you wrote may not be actually what you were intended, because the compiler finds it odd or not standard.
You didn't have the warning before probably because it wasn't activated by default in previous versions of Xcode. The latest version of Xcode5 activates more warnings (which is a good thing, as it warns you about more things that could go wrong in your code and encourage you to fix them), hence this new one you have but didn't have before.
As I understand what you describe, tour usage of a constant is incorrect (and that's probably why Xcode emits a warning).
The correct way to declare a constant that you want to be accessible from multiple files is to:
Declare it (define its existence and type) in a header (or in your pch) like this: extern <type> const <name>;
And define it (give it a value) only in one implementation file (like your main.m, your AppDelegate.m, some Constants.m file, whatever) like this: <type> const <name> = <value>
Some details and reminders about constants declaration (also valid in standard C)
You use static <type> const <name> = <value>; in an implementation file only, when the constant is local to the file and does not need to be used by other files. In that case, you declare it typically in the .m file in which you will use it, and other files won't have access to it (which is quite what the static keyword means, actually (making the constant attached/local to the file).
In that matter, you should never declare a constant that way in a header file (and especially not in your .pch file), because header (and pre-compiled header) files will be included multiple times. If you do that, this would declare as many independent constants as the number of implementation files you include your headers into (this has evil side effects especially for pointers/objects, for exemple declaring an NSString* const that way -- for, say, using it as a notification name of error domain -- will create multiple string constants, with the same value but different addresses, which will probably not behave like you will expect)
When you need to declare a constant that you need to use / be accessible from multiple implementation files, so declaring this constant in a header file so that it is known to all implementation fiels that includes this header, you need to only declare it in the header, and not making it static (at this would run against the purpose of having the same constant for all files instead of multiple independent instances of the constant) but instead indicate extern to let the compiler know that its definition (value) is set elsewhere. Hence the solution given above.
I defined both area/1 and perim/1 in modules sqaure and circle.
I want to import and use them in another module. Here is my import statements:
-import(square, [area/1, perim/1]).
-import(circle, [area/1, perim/1]).
I got these error messages.
~/test.erl:4: function area/1 already imported from square
~/test.erl:4: function perim/1 already imported from square
I know erlang does not support namespace. But since we can qualify a function call by specifying the module (i.e. square:area vs circle:area), I fail to see how the lack of namespace is the source of the error here.
So, what exactly caused the above error and how can I fix it?
In Erlang, "importing" a function from another module means being able to call it as if it were a local function, without the module prefix. So with this directive:
-import(square, [area/1, perim/1]).
you could write area(42) and it would mean the same as square:area(42).
However, if you include area and perim functions from two modules, it would be ambiguous which one you'd actually call when writing area(42).
As you correctly note, you can always qualify the function call with the name of the module, i.e. square:area(42) and circle:area(42) - so I would suggest doing so consistently and removing both import directives. This is also recommended by rule 6.6 of the Erlang Programming Rules - "Don't use import".