To reproduce:
- Create a new project Proj. Set the working directory and the project
root to some directory Proj.
- Create a new file "SomeClass.java". Define it in package "pkg". Save it
in location "Proj/src/pkg".
- Compile. Compilation succeeds.
- Type "SomeClass c" in the interactions. An "Undefined class" error
occurs. The interactions classpath contains "Proj", but not "Proj/src".
I don't know if the intended behavior is to allow the source root to be a
subdirectory of the root (as is done during compilation), or to force it to
be the same (as is done in the interactions pane). But that choice should
be consistent.
Other operations that depend on a classpath (like Javadoc) should be
made consistent as well.
Logged In: YES
user_id=430590
By definition, the project root is the root of the project
source tree. So the term "source root" as used in the
preceding post is synonymous with "project root". In the
DrJava source code, the term "source root" is applied to
individual files: the source root for a file is the
directory where the file's path name is rooted (assuming the
file is properly named).
Using this terminology, the example that cite is a file in a
project source tree has a source root distinct from the
project root. Such a file will not be found when the
interpreter tries to load it or when you try to execute
java pkg.SomeClass
and the directory containing "pkg" ("src" in your example)
is not on the CLASSPATH.
On the other hand, javac is more permissive; it will compile
files that are placed in the wrong directory as long as it
can find all of the files required for compilation using the
CLASSPATH. The behavior that you describe is consistent
with the permissive rules used by javac. Exactly the same
thing happens using the command line interface. Try
compiling SomeClass.java at the command line with the
project root (the directory containing "src") as the only
entry on the CLASSPATH. (I don't think the compiler even
requires the file to be located in a directory called
"pkg".) If you give the relative path name to the file
SomeClass.java, compilation will succeed (for a trivial
class that does not refer to any classes outside of the Java
core libraries). Then try executing
java pkg.SomeClass
It will fail. Try moving to any other directory (so that
"src" is not on the CLASSPATH) and executing the same
command; it will still fail.
When you execute
java <fully-qualified-class-name>
the JVM searches the CLASSPATH for such a class. The
working directory is irrelevant (except for fact that "."
may be on the CLASSPATH). On the other hand
javac <relative-or-absolute filename>
compiles the specified file assuming that it is properly
located in some source tree but it does not check that the
location is correct. The source root for the file does not
have to be on the CLASSPATH as long as javac can find all
referenced files in either the core libraries on classes on
the CLASSPATH.
Logged In: YES
user_id=1060117
I see that you're right about javac. There is no way to force it to check that
the files it compiles have a certain source root.
As I understand it, there are three places where the source
root is used in DrJava:
1) It is used in the sourcepath passed to javac, and possibly
the classpath (the latter only when there is no project build
directory)
2) It might be passed to javadoc as a sourcepath (not sure
about this)
3) When there is no project build directory, it is added to
the classpath for everything that requires a classpath
(notably, the Interactions Pane)
Despite that, I can't seem to find any combination of
project and single-file compilation steps in DrJava that
will lead the compiler to complain about not finding a
needed file. I have even tried referencing files in a
different package in the source tree, and javac seems to
have no trouble finding them. (I would have expected
the incorrect classpath or sourcepath that is apparently
passed to javac to cause trouble when dealing with
interdependent files, but that doesn't seem to be the case.
This is strange, because when I compile a single file on
the command line, I have to provide a correct sourcepath
or compilation fails. So maybe there's something I'm
missing.)
Javadoc doesn't seem to care what DrJava thinks the
source root is, either.
So if I'm right, the only way to observe that something is
wrong -- that the convention <Project Root> ==
<source root> is not being followed -- is when class files
need to be located within the source tree. Since that makes
the convention difficult to enforce, why not just abandon
the assumption that it holds? We can do so either by
calculating the source root(s) ourselves (an expensive
operation), or by accepting the fact that we just don't know
what the source root is. If we require a project build
directory to be set (and providing one by default), rather
than allowing class files to be created in the source tree,
I think all dependencies on the source root will be removed.
Most other IDEs automatically generate a build directory
anyway, and I can't think of a compelling reason to prefer
generating class files "in place".
On the other hand, I can envision a lot of users wanting
the project root to correspond to the "top" of a project,
which in many cases (DrJava on Subversion included) does
not correspond to the source root.
Logged In: YES
user_id=430590
I don't understand what is broken in our current
conventions. I see no reason to force the user to create a
separate build directory. This may be appropriate for
production programming, but for small course projects it is
overkill. If you simply use the command line interface, the
source tree is the natural place to put class files.
The compiler is willing to accept a list of input files that
have multiple source roots regardless of whether they are on
the classpath; it may add the inferred source roots for each
file to the classpath for resolving external references. I
have not tried any experiments that depend on such
additions. On the other hand, the JVM ("java" command) only
loads classes that are on the classpath. Our interpreter
runs within a JVM and hence obeys the same conventions.
In flat file mode, we infer a source root for each open
files and add it to the classpath, which caused unexpected
behavior in some cases before we started resetting the
interactions pane on every compilation and unit test
invocation. Old versions of class files in inactive
directories (containing files that were open but
subsequently closed) could be executed in preference to
those that have just been compiled. The only common
situation where we can still see this anomalous behavior is
closing all files in flat file mode followed by opening a
collection of source files that have already been compiled.
The source roots for the files that were closed will still
be on the classpath. I am seriously considering modifying
DrJava to reset the interactions pane when all files are closed.
For projects, we only add the project root (source root for
the project) if there is no build directory or the build
directory for ALL of the project source files. We do not
individually determine the source root for each file and add
it to the classpath. On the other hand, if auxiliary files
(files not in the project source tree) are opened, the
source root for each such file is added to the classpath.
I insisted on only adding the project root or build
directory for the files in the project source tree because
this convention prevents projects from being set up with
inconsistent package names. If such a project were run
outside of DrJava, it would obviously break.
Resetting the interactions pane only changes the classpath
if files have been closed or project/user settings have been
changed since the last reset. The source roots for these
files will not be added the class path when the interactions
pane is reset. The classpath is determined by what
files/projects were open when the interactions pane was last
reset plus any new files (outside of the project source
tree) that have been opened since the reset.
Logged In: YES
user_id=1060117
Here is the problem with our current conventions: the program assumes that
the root if the source tree is the project root, but the user is never told about
this assumption. When a user doesn't follow that convention and then things
go wrong (the Interactions pane doesn't recognize a name), the user doesn't
know why or how to fix it. He will probably come to the conclusion that
either projects or the Interactions pane are "broken."
Yes, the same setup wouldn't work from the command-line. But at the
command line, the user expects to specify all the relevant parameters to
make things work. In DrJava, the user is used to the program just figuring
these things out for him. The natural expectation is that if the sources are
open and have been compiled, the classes they define can be used in the
Interactions pane.