- Create the new C++ "Shared Library". Symbols are exported by default by GCC; no need for declspec as used for MSVC. For more precise control of symbol visibility, consider the lib-symbol-visibility module for GCC 4.0+ (http://www.gnu.org/software/gnulib/manual/html_node/Exported-Symbols-of-Shared-Libraries.html).
- In library client's project settings, add entry to compiler include directory listing: "C/C++ Build > Settings > Tool Settings > GCC C++ Compiler > Includes"
- Add entry to linker libraries listing: "C/C++ Build > Settings > Tool Settings > GCC C++ Linker > Libraries". Shared libraries in Linux follow the naming convention libXYZ.so, where "XYZ" is the actual name of the shared library. Use the library name, and NOT the full file name, for this entry. (See http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html .)
- Add an entry to the linker library search path listing on the same settings pane. This is the directory that contains your shared .so file.
- In library client's project settings, Create a reference to the shared library project, so it will be rebuilt as necessary: "C/C++ General > Paths and Symbols > References"
- Build the client.
Make sure the library loader can locate the shared library. Permanent libraries should be installed to one of the locations referenced by /etc/ld.so.conf . You may wish to add an entry by including a new file under /etc/ld.so.conf.d . Development libraries can be referenced by exporting
LD_LIBRARY_PATH. To diagnose problems, exportLD_DEBUG=files.Note that other considerations are necessary for permanent libraries, such as versioning and symbolic link creation via
ldconfig. See http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html .
ThoughtFlows
C++ Shared Libraries with Eclipse CDT on Linux
Doc Bites - XPathExpressionException
A bit of documentation can save a lot of frustration. Take the following code, for example:
import javax.xml.xpath.*
import org.xml.sax.InputSource
def xml =
'''
<foo>
<bar>
<baz>qux</baz>
</bar>
</foo>
'''
def reader = new StringReader(xml)
def source = new InputSource(reader)
def xpath = XPathFactory.newInstance().newXPath()
def nodes = xpath.evaluate('/foo', source, XPathConstants.NODESET)
println nodes.getLength()
Looks reasonable, right? And when you run it, everything works!
1
Now let's say we want to evaluate a few more XPath's:
import javax.xml.xpath.*
import org.xml.sax.InputSource
def xml =
'''
<foo>
<bar>
<baz>qux</baz>
</bar>
</foo>
'''
def reader = new StringReader(xml)
def source = new InputSource(reader)
def xpath = XPathFactory.newInstance().newXPath()
def nodes = xpath.evaluate('/foo', source, XPathConstants.NODESET)
println nodes.getLength()
nodes = xpath.evaluate('//bar', doc, XPathConstants.NODESET)
println nodes.getLength()
This yields:
1 Caught: javax.xml.xpath.XPathExpressionException at test.run(test.groovy:24)
What the-? Running in GroovyConsole provides a better clue:
javax.xml.xpath.XPathExpressionException ... Caused by: java.io.IOException: Stream closed
Ok, but why? The documentation on XPath.evaluate() doesn't mention any limitations on invoking the method multiple times. The title of this post may have tipped you off - the documentation, in this case, has a major bug.
When fed an InputSource, XPath.evaluate() will close() the underlying reader or stream after it has completed evaluation! When you try to call evaluate() again, BOOM!
The alternative is to feed in a DOM node:
import javax.xml.xpath.* import groovy.xml.DOMBuilder def xml = ''' <foo> <bar> <baz>qux</baz> </bar> </foo> ''' def reader = new StringReader(xml) def doc = DOMBuilder.parse(reader) def xpath = XPathFactory.newInstance().newXPath() def nodes = xpath.evaluate('/foo', doc, XPathConstants.NODESET) println nodes.getLength() nodes = xpath.evaluate('//bar', doc, XPathConstants.NODESET) println nodes.getLength()
Which runs correctly:
1 1
The moral of this episode? For code you're exposing to a wide audience, take the time to document gotchas. If your users don't thank you, at least they won't curse you!
Brownie points: use Groovy's DOMCategory to make dealing with the nodes returned by the XPath evaluation a similar experience to working with XmlParser or XmlSlurper:
import groovy.xml.dom.DOMCategory
...
def nodes = xpath.evaluate('/foo', doc, XPathConstants.NODESET)
println nodes.getLength()
nodes = xpath.evaluate('//bar', doc, XPathConstants.NODESET)
println nodes.getLength()
use (DOMCategory) {
println nodes.baz[0].text()
}
Prints:
1 1 qux
Rock on with XPath!
Reporting a Visual Studio Bug
I was up late last night refining a bug report for an issue I discovered in Visual Studio 2005. Unfortunately, it is no longer possible to report issues for 2005 on Microsoft Connect.
Ok, I thought, let's reproduce the issue on a version which is still accepting feedback. So I went ahead and downloaded the Express version of Visual Studio 2008. I should have known that they labeled it "Express" for a reason:
- Visual Assist X doesn't support Express
- Instead of devenv.exe, the IDE executable is called VCExpress.exe
- VCExpress.exe does not support command line builds!
What the latter item especially amounted to was much time wasted editing and refining my test case. Written in Perl and originally targeting Visual Studio 2005, it uses devenv.exe to perform a series clean and build cycles, which is the only way to demonstrate the race condition easily in a repeatable fashion.
Luckily, earlier in the day I had installed the recently released Visual Studio 2010 RC. I was also able to reproduce the issue there, so that is where I finally filed the Connect ticket.
I appreciate the steps Microsoft has been taking to make their product feedback process more transparent and accessible to users. However, imposing version-based limitations to file issues that may well be unresolved across several iterations of a product will discourage users from reporting bugs - many / most users probably would have given up when they saw that tickets were no longer being accepted for Visual Studio 2005, or whatever versions they actually have a license for.
Of course, I realize there are business and practical reasons Microsoft might be doing this. It just may be counterproductive in certain cases - clearly, this is the case for carry-over bugs.