Community
Participate
Working Groups
I have changed all the team plugins to use the PDE classpath container. At some point since I set it up, all my .project files have change to include a fragement that I have loaded but is not a dependency of the project (the core resources spysupport fragment). This automatic changing has happened a few times. The first time, I wasn't sure if it wasn't because of something I did so I just replaced the .project files with what was in the repository. However, I just noticed that they are all changed again. This should not happen.
I just remembered that I may have performed an Update classpath on a plugin since the last time I reverted the .projects (I'm not sure of the timing). However, even if I did, the .project file for other projects should not be effected. I would even argue the the .project file should not be effected at all when the classpath is updated.
The .project modification is done by JDT Core. cc'ing Philippe to shed some light on why that is necessary.
In order to induce the proper build order, we have to record project references (in the platform way) for each Java project prerequisite on the classpath. This is why we update the project description so as to ensure references are adding according to the classpath. This is not a happy story, but this is the only existing solution (since day 1).
Is there no way I can prevent the fragment from getting on the classpath? It is not required for the plugin but is being put there by the PDE classpath container. I don't really understand the relationship between plugins, fragments and classpaths but it does seem a bit odd that adding a fragment to my workspace would cause projects that didn't require the fragment before to all of a sudden require it.
If the PDE container states a fragment, then we will add it as a project reference.
Fragments have to be on the classpath, if PDE plans on maintaining its claim that it provides a development environment that is as close as possible to the runtime environment. This is not negotiable. This is a big issue that goes beyond fragments, and has nothing to do with fragments. As you delete projects from your workspace or add projects to your workspace, the classpath of the other projects is recomputed dynamically by PDE to reflect the new environment (and hence the luxury of classpath containers). The .classpath file does not change. However, since the newly recomputed classpath depends on a different set of projects (since some have been deleted/added from the workspace by the user), JDT Core goes in there and modifies the .project file. So whatever the consistency that we gained by maintaining an unchanged .classpath file is undermined by the instability of the .project file.
I will add DJ to the discussion because ultimately this is a platform core issue. DJ, can you shed more light to the relationship between project references and builders? It seems to us that the dependencies between the projects (i.e. if a project A references project B and B changes, A must be built as well) are somewhat leaking too low in the component stack.
Note: by putting fragments on a plugin classpath, you allow plugin code to directly target fragment code. The .project modifications are mandatory as per platform build management design. I would love to get rid of the project reference setting, and let others do it for us. The 'simple' problem is to get the build order right. This is achieved by a topological sort of project references (remember that platform knows nothing about Java, so it doesn't care about a classpath). What would be better than static project references in the project description would be dynamic project references answered by each builder/project nature. This change would have to come from the platform side. Until something like that occurs, there is nothing JDTCore can do without breaking the build management.
OK, lets hear the platform core guys - it would be really good if we could get this problem fixed because we think that dynamic classpaths (that's how we re- branded our use of classpath containers :-) are 'the' way of selfhosting for Eclipse 3.0. We would like to make it the default but we need to fix these issues if possible.
Assigning to John A. to see what he can do.
My opinion: I don't believe the fragments should be auto-included in a plugin's classpath. A plugin should define its API. If it explicitly includes something from a fragment (like swt), then the fragment's contents can be included. In other conditions, the fragments should not be on the classpath of a plugin.
What about the following common case: plug-in: org.eclipse.core.tests.resources fragment: org.eclipse.core.resources.testsupport (fragement for resources plug-in) The fragment provides public classes/methods for package visibility code so we can test it. The tests project needs to have the fragment on its classpath to compile. We also have this case in our spies/tools plug-in.
Taking DJ's case into account, that is why PDE adds a fragment project directly to a plug-in's classpath only if the fragment project contain a source folder.
Right, but this doesn't mean core.resources classpath should include its own fragments for free. If you read original reporter's problem, he was concerned that switching to PDE container was adding gratuitous project prereqs. If my test plugin was targeting the fragment, then in the past it would have explicitly referred to it on its classpath to be able to compile against it. Using the PDE container shouldn't change the set of project references. For instance, you don't want to allow core.resource developpers to code against their metrics fragment...
The spy fragment was never on the org.eclipse.core.resources project's classpath. It was on the org.eclipse.core.tools project's classpath. org.eclipse.core.tools explicitly imports org.eclipse.core.resources and that is why it got the spy fragment as part of the deal because the spy fragment is a fragment for core.resources.
To further clarify things: A fragment project contains a project reference to its parent plug-in. The parent plug-in never has project references to its fragments. However, clients of the parent plug-in should be able to have visibility to all the code of the parent plug-in and all that plug-in's fragments.
I see, sorry for the confusion. Still I find suspicious that fragments are automatically attached to dependents. I had the feel that a fragment was only an implementation detail of a particular plugin. Thinking of swt, the win32 or linux implementation pieces. I start to wonder if the spy fragment shouldn't rather be a separate plugin, normally prereq'd by the test project...
Actually, we also had a problem with swt fragments on gtk. This fragment needed to be explicitly on the classpath of clients of the swt plug-in; otherwise the JDT compiler would complain that indirectly referenced class files are missing from the classpath of the client plug-in. For a trip down memory lane, see bug 34128.
This one is special, as it does not have any API on its own, but rather reexport its entire fragment. Do we think of fragments as addendum to a plugin or simply an implementation detail ? I understand however that this is tricky for you to make the clear distinction in between these 2 cases. Ideally, you'd like to always reexport fragments so that swt would be happy by default.
We wouild be happy to simplify our classpath computation regarding fragments if all the use cases listed in this defect are handled in a different way. SWT case may be a hard problem, though. If we ask all the teams that reference classes in their fragments from their plug-ins to simply convert these fragments to dependent plug-ins, then we will end up with SWT to handle. Perhaps a solution would be to treate SWT as special (have an explicit knowledge of org.eclipse.swt in our code). This is a little goofy but at least we would not impose a strange rule on every fragment because of one internal use case.
You could funace the rule like below: When the plugin.xml references a library JAR which happen to live in a fragment, then you could offer to export the fragment to dependents (swt case) ? If not, then you'd do nothing by default. The test project would have to explicitly reference the spy fragment (as it probably did in the past anyway). But I presume this shouldn't even be necessary. Bug 34128 was not further investigated. Do we really need the special rule for swt ? Could have been nothing but a bug ? Suggest bug 34128 is further analyzed.
Re comment #19, it is true that swt is a special case, i.e. the swt library is declared in the plugin.xml, yet it's packaged in the fragment. Note however that PDE is able to model that at development time on win32 for instance without having to add the fragment to clients of swt. The reason why the gtk fragment needs to be added on that platform is because the swt.gtk fragment contains an extra library swt-pi.jar. And whenever a plug-in references the type Composite in their code, the JDT compiler starts wanting to resolve types declared in the swt-pi.jar and complains when they're not found. Adding the swt.gtk to the classpath of the client, whether or not it's rightly justified, solves that problem. So my "conjecture" is that the JDT compiler is too eager to resolve all types referenced by Composite, including ones from the swt.gtk fragment, to put them on the classpath of the client plug-in, and complains when it does not find the type coming from the fragment. We should investigate whether this is a bug in the JDT compiler or if other compilers exhibit the same behavior.
Bug 34128 has now been resolved and clients of swt no longer need the swt.gtk fragment on their classpath to compile. I'm sensing that the direction we want to go is to impose a limitation that if a plugin A imports plug-in B, and plug-in B has a fragment: then plug-in A cannot directly reference classes in plug-in B's fragment. Note however that this new limitation will break DJ's scenario (comment #12) and similar testing setups for the Help team (and other people who, I'm sure, will become pretty vocal if we go in this direction). Their argument would be of course, that plug-in B's fragment is available to plug-in A at runtime, so why is it not available at development time. Incidentally, none of this fragment-related conversation has anything to do with the subject of this bug report which is the fact that the .project file is being overwritten.
While we're at it, let's add Jeff to the discussion to see his take on how this might affect fragments in the Equinox world.
In comment #23 it is proposed "that if a plugin A imports plug-in B, and plug- in B has a fragment: then plug-in A cannot directly reference classes in plug- in B's fragment." Did I miss how one gets SWT code on their classpath (it is all in the fragment)? Or ui.win32 (activeX api is in the fragment)? To me the simplest story to explain is the one that has the dev-time classpaths model the runtime classpath as closely as possible. This reduces the incidence of "but I could see that at compile time!" and "why cant the compiler see it, its there a runtime?" The problem at hand is the collateral damage to the .project file not so much the value of the classpaths. While fragments are largely used to express implementation detail, there is nothing in any of the design or doc to discourage people from putting API in there. As we have seen Eclipse does it with SWT and ui.win32. In the absence of being able to spec a dependency on a fragment, it makes sense to put the fragment code on the classpath (how else will it ever get there?). In Equinox we used to treat fragments as first class entities and plugins were allowed to express dependencies on them. So JDT could say it requires ui and ui.win32 (just examples). Under this model it is clearer that the classpath should not include the fragments for free. If you really do depend on ui.win32 you can state it in the plugin.xml. This has the significant drawback of encouraging/promoting platform- specificness up. This is especially true in the SWT case where all of the API is in the fragment so to get anything you would have to make a platform- specific dependency. Side note: SWT is an anomoly and I really don't remember why the plugin.xml contains the library decl but the jar is in the fragment or why the API is not in the plugin. Perhaps this can be changed? Also note that Equinox has since moved from independent fragments to merged fragments (the classic Eclipse model) to maintain backward compatibility and allows package visibility between fragments and their host plugin.
To make it clearer how the statement from comment #23 covers the swt case, it should be rephrased as: "if a plugin A imports plug-in B, and plug-in B has a fragment that declares a library in its fragment.xml, then plug-in A cannot directly reference classes in a library declared by plug-in B's fragment". swt.jar is declared in the swt plugin.xml, so it will still be visible to clients of swt, although it is physically located in the fragment. swt- pi.jar, for example, which is declared in the swt.gtk fragment will not. I, for one, am in total agreement with remarks made in comment #25. "While fragments are largely used to express implementation detail, there is nothing in any of the design or doc to discourage people from putting API in there." This statement says it all. If we now introduce a new limitation to not allow client plug-ins to directly reference code declared by fragments, it will break at least one existing and perfect valid scenario for many people, e.g. DJ's setup. And that's one scenario too many. The bottom line is if a library is on the runtime classpath, it ought to be on the development classpath.
I still disagree, and would rather force people requiring APIs located in fragments to declare these dependencies explicitly. To summarize, I don't want JDT Core to see any spy functionalities when coding. At runtime, I don't care since I will not invoke them since I did not code against these. All coding tools are expecting the classpath to determine what is expected to be accessible. Compile-time is different from runtime. Following your argument of making the dev classpath be the same as the runtime one, you could add all other projects even indirectly referenced from a plugin.xml, as this is exactly what will occur at runtime... isn't it ? I certainly wouldn't want that.
If I may shed some light on SWT 'special case', it has been a particular architecture choice that led to this. Erich Gamma can talk for hours about one of the dearest patterns in his book (the factory) and multi-platform widget toolkits are one of the classic use cases. In this pattern, all the widgets would be first defined as interfaces (IButton, IText etc.). There would be also a factory interface (IWidgetFactory) with methods like IButton createButton() etc. To create a button, one would need to call 'WidgetToolkit.getFactory ().createButton()'. Depending on the os/ws/arch, the correct factory instance will be created, dolling out concrete os/ws/atch implementations of widgets. In this architecture, SWT plug-in would contain interface declarations, while fragments would contain conrete implementations. Nobody would need to have SWT fragments on the classpath because no plug-in would access internal implementations of interfaces directly. SWT team argued that this approach leads to duplication (each widget has an interface and N implementations) and lots of code that would affect performance. Instead, they are using Java's late binding to achieve the same goal. When your code says 'Button button = new Button(...)', the actual Button class is resolved to a different 'real' class depending on your classpath. There is no 'common' declaration of a button - there is a "Button' class for each platform that happens to have the same API, so your code always compiles. With this approach, there is no common code to put in SWT plug-in, so SWT fragment must be put on your classpath. Erich and myself spent one afternoon ages ago trying to solve the SWT classpath problem and gave up in frustration - there is no way around the fact that SWT case is 'special' and Eclipse developers should be discouraged from copying it. Needless to say, there is no way SWT will now be redesigned to use the toolkit+factories architecture :-).
I'm sorry to interrupt this interesting discussion, but I have entered a new bug report (bug 46668) for the problem of changes to the .project file. Note that this problem in the abstract is completely unrelated to fragments. I am renaming this bug report to better reflect the majority of its discussion.
To me the most important argument against adding fragments to the classpath is this: since a plugin cannot explicitly require a fragment, your plugin cannot safely assume that it will be there at runtime. Thus automatically making it available at compile time is inviting trouble at runtime. As Jeff argues, this also encourages creeping fragment (and platform) dependence that will come back to bite people when they discover that they can't rely on the fragment always being there. The approach used by the core spy plug-in and help tests is a hack: these plugins will break at runtime if the fragment they rely on is missing. In controlled scenarios like testing and "spy" tools this may be acceptable, but it is not a scenario to be designing general plugin tools against. The ui.win32 fragment is also not a good example. The UI plugins don't compile against this fragment (since it's unsafe to assume it will be there at runtime). This leaves only SWT, which I think we all agree is an anomalous case. I suggest the following: - PDE never adds fragments to the classpath of downstream plugins - The "atypical" cases that do want to compile against a fragment (spy and tests) can add the fragment pre-requisite to the classpath manually as a separate entry (as they have always done in the past). By requiring these special cases to add the dependency manually, we are reinforcing that this is not normal behaviour that will necessarily reflect the runtime situation, and they are responsible for their own breakage if that fragment is missing.
Concur with John A's proposal. fragments were not intended to provide API for a plugin. I don't have a problem that they can be used this way, but we don't want to optimize the tooling for this case. It is valuable occasionally (DJ's case is an example), but we do not want to encourage this style. The "normal" situation is that plug-in developers should write plug-ins that depend on other plug-ins.
I third John A proposal :-) I also want to add two more facts about SWT that I learned from SWT and UI teams: (a) The SWT project in the repository is a single project - there are no projects corresponding to the OS-specific fragments. When you load this project from CVS, you need to follow manual instructions prepared by the SWT team to get the SWT project itself to compile. This instructions involves replacing the Java .classpath file. (b) If you import SWT the plug-in and fragments as source, they do not compile. This has never been an issue. People who want to see but not touch SWT source simply import its plug-in and fragments as binary. And people who want to see and possibly modify SWT source load the real SWT swource project from the CVS repository.
>Following your argument of making the dev classpath be the same as the >runtime one, you could add all other projects even indirectly referenced from >a plugin.xml, as this is exactly what will occur at runtime... isn't it ? I >certainly wouldn't want that. I am not sure what you are referring to here, but I hope you are not talking about reexported imports. They are indeed added to a plug-in's classspath. How else would it compile? PDE also adds core.boot and core.runtime to all plug-in's classpath, as these two plug-ins are implicitly available at runtime to all plug-ins (in a non- Equinox world, that is). Plug-ins do not have to declare core.boot and core.runtime as dependency in order to gain visibility to their libraries.
Wassim, you mentioned that Help component has a fragment case that we needed to support. What category does it fall in?
I believe it fell under the test project category from comment #12. I remember Konrad checking out his test project from CVS, using PDE to update its classpath and being shocked that the project did not compile because one of his plug-in's fragments was in source form and not picked up by PDE. Note that if plug-ins and fragments are in binary form, then fragments are not added to a client's classpath because their libraries can be directly accessed through a project reference to the parent plug-in.
Fixed. In summary, The classpath of a plug-in project will contain: 1. the libraries declared in its plugin.xml 2. all its direct dependencies and reexported imports of its direct dependencies. The classpath of a fragment project will contain: 1. the libraries declared in its fragment.xml 2. the libraries declared in its parent plug-in's plugin.xml 3. The fragment's direct dependencies and reexported imports of these direct dependencies. 4. Its parent plug-in's direct dependencies and reexported imports of these dependencies. Plug-ins that will be added for free to all classpaths (both fragments and plug-ins) are core.boot and core.runtime. These free dependencies are not added to the core.boot and swt plug-ins. They are not added to any plug-in if Eclipse is in OSGi mode.
*** Bug 45686 has been marked as a duplicate of this bug. ***
*** Bug 45732 has been marked as a duplicate of this bug. ***