Hi Jeremie,
I invested some time today, and I after changing the code of the cppcheck a bit (added virtual to some methods in CppCheckExecutor so I can overload them) I created a new class CppCheckExecutorNetwork, which by the name of it you can understand that it redirects all its output and input to the network using the code the codelite_indexer uses (unix sockets / named pipes)
So now, you can start the cppchecker like this:
Code: Select all
./cppchecker -s --all --daemon=<codelite process id> --xml
the cppchecker will remain up and will wait for connections.
In your code, you use the following code fragment:
Code: Select all
// Include files
#include "../network/cppchecker_request.h"
#include "../network/cppchecker_protocol.h"
#include "../network/named_pipe_client.h"
#include <stdio.h>
// Some macros needed
#ifdef __WXMSW__
#define PIPE_NAME "\\\\.\\pipe\\cppchecker_%s"
#else
#define PIPE_NAME "/tmp/cppchecker.%s.sock"
#endif
to establish connection to the cppchecker:
Code: Select all
// build the channel name
char channel_name[1024];
sprintf(channel_name, PIPE_NAME, argv[1]);
clNamedPipeClient client(channel_name);
Construct a request object:
Code: Select all
CPPCheckerRequest req;
req.setFile("C:\\Development\\C++\\codelite\\trunk\\Subversion\\subversion.cpp"); //set the file to be parsed here
Connect to the cppchecker and send the request
Code: Select all
client.connect();
CPPCheckerProtocol::SendRequest(&client, req);
At this point, if SendRequest returned true, we can start reading for the reply. Now, the 'reply' object has a completion code which needs to be checked as below:
Code: Select all
bool cont( true );
while ( cont ) {
CPPCheckerReply reply;
if ( CPPCheckerProtocol::ReadReply(&client, reply) == false ) {
// error
break;
}
switch ( reply.getCompletionCode() ) {
case CPPCheckerReply::StatusMessage:
printf("STATUS: %s\n", reply.getReport().c_str() );
break;
case CPPCheckerReply::CheckingCompleted:
printf("STATUS: Completed\n");
cont = false;
break;
case CPPCheckerReply::CheckingInProgress:
printf("REPORT: %s\n", reply.getReport().c_str() );
break;
}
}
In the above code, I am reading a replies from the cppchecker daemon. Until a reply with completion code 'CPPCheckerReply::CheckingCompleted' has arrived or CPPCheckerProtocol::ReadReply returned false, it is safe to assume that we are still reading the output for the last file we sent.
In addition there is CPPCheckerReply::CheckingInProgress which means, we got partial report, keep it in a buffer until you get the CheckingCompleted status.
Requests with CPPCheckerReply::StatusMessage completion code, are messages reporting progress (current file name, precentage)
I checked this code using a demo client and it works flawlessly.
The above code can be implemented within a worker thread, which will send wxEvents to the GUI whenever it receives StatusMessage completion code replies from the cppchecker.
There are many advantages to the above code:
- If cppchecker crashes, codelite is still up and can also bring the cppchecker back to live (search the code for codelite_indexer similar implementation)
- The daemon is up and running so no need to waste time for forking the process (which is slow on Winodws) for each file
- We can build our own list and send the files one by one to the cppchecker daemon (similar to how it is done in codelite_indexer)
- It uses very fast IPC (inter process communication) layer - which is very fast and stable ( the sources were taken from the code I wrote for the indexer ) it uses named pipes on Windows and Unix socket on Linux/Mac
- Very simple C++ API usage wrapped with 3 classes: CPPCHeckerReuqest, CPPCheckReply and CPPCheckerProtocol
Let me know what do you think!
Eran