Upgrade from Wt3 to Wt4
Added by Diego Villalpando over 2 years ago
Hi,
I was wondering if there is a guide/best practices on how to upgrade a Wt3 project to Wt4.
In the next couple of months, Im planning on upgrading one large project that I have been working on since version 3.2.1.
Currently Im running version 3.3.12 wondering if it makes more sense to upgrade first to the latest 3.7.1 version before upgrading to 4.5.1.
Also, will Wt3 stream support ever stop?
Any tips/advice is greatly appreciated.
Thanks!
Diego Villalpando
Replies (2)
RE: Upgrade from Wt3 to Wt4 - Added by Roel Standaert over 2 years ago
We already no longer support Wt 3. It's been EOL since January.
I think you won't have to change much if anything if you update to 3.7.1 first. I think it may be worth doing, though. If you do encounter regressions with 3.7.1 you may want to check the release notes for 4.5.1 to see if it hasn't been fixed in the meantime. The release notes for Wt 4.0.0 and the blog post already contain some information about what has changed in Wt 3.
Firstly I would recommend that you get up to speed with recent C++ versions and move semantics if you aren't already. Wt 4 expresses ownership according to the C++ Core Guidelines:
std::unique_ptr<Object>
expresses unique ownership (used for most widgets in the widget tree)std::shared_ptr<Object>
expresses shared ownership (used e.g. forWButtonGroup
,WAbstractItemModel
,...)Object*
andObject&
are non-owning.- No "naked
new
" ordelete
: usestd::unique_ptr<T>(new T(...))
,std::make_unique<T>(...)
,std::shared_ptr<T>(new T(...))
, orstd::make_shared<T>(...)
.
Big changes you will notice:
Header files¶
Wt's header files now have a .h
extension. There's a Python script in Wt's source tree: wt4_add_h_to_includes.py
, which will change the includes of all the files in the current working directory. This will probably be the first thing you need to fix.
Smart pointers¶
As I mentioned before, Wt 4 uses smart pointers to express ownership, so here are some likely changes you will have to make:
// Given some Widget type, and a WContainerWidget *container
Widget *w = new Widget(..., container);
Will become:
Widget *w = container->addNew<Widget>(...);
This is a shorthand for:
Widget *w = container->addWidget(std::make_unique<Widget>(...));
If the adding of a widget and its creation are split up:
Widget *w = new Widget(...);
...
container->addWidget(w);
Then it will be:
auto w = std::make_unique<Widget>(...);
...
container->addWidget(std::move(w));
Note that w
will be null after the call to addWidget
. You may want to save the result of addWidget
, or call w.get()
if you want to still refer to the widget you just added.
If we encountered the above situation when porting, we would usually either reorder things so that the addWidget
calls happens first rather than last, or write it as such:
auto wPtr = std::make_unique<Widget>(...);
auto w = wPtr.get();
...
container->addWidget(std::move(w));
WTemplate
similarly has a bindWidget
that returns a raw (non-owning) pointer, and a bindNew
. The layouts also have addWidget
functions that return a raw pointer.
Enums¶
In Wt 4 we changed most enums to scoped enums (enum class
). Many things that were prefixed now no longer use a prefix, and many enums that were in a class's scope have been moved to the namespace, e.g. Wt::WContainerWidget::OverflowAuto
becomes Wt::Overflow::Auto
. The search function in Wt's documentation may help you find the correct substitution.
Your code will likely not compile before you fixed all of these issues. I recommend that you turn on as many compiler warnings as you can. I also recommend using static analysis tools like clang-tidy. This will help you catch common issues like dereferencing unique_ptr
after a move. Once you've resolved compilation errors and warnings you should be most of the way there.