An honest question. As game engine developer, I decided to use spdlog just as you, and was really interested, how do you tackle compile time? From my experience It adds from 2 to 5 seconds of compile time per file... I wonder, have you ever tackled this issue?
@@TheMesoria My experience with header only libraries is that you can either put them into a precompiled header file, or you abstract them into your main library. As a software developer, I see far too often people including header files within header files because their class contains a pointer/reference to an object. This is what slows build times because those header files need to be parsed for each cpp file that gets compiled. Making a change in a header file might propagate throughout your entire build hierarchy and your build system will want to build everything again. If you are still having problems, there are a few methods you can try. 1. Use a Pimpl method if you have objects that really need their header files included. This pointer to implementation is quite good at abstracting your private fields of the class to inside of you source file. This is also very useful to contain those nasty header files with a ton of macros that cause more problems than they solve. This does mean another level of indirection to access your variables though. Perhaps the compiler can optimize this though although I have never tried to see if this was the case. 2. Move your header files to your source file and forward reference what you need in the header file. Quite often, you only need the type, and including the header is just wasted build time. 3. Use precompiled header files. Put a lot of the header files that you would otherwise end up including in your other source files into a precompiled header. A lot of the work will have already been done by the compiler, but I believe this might need to be used wisely. I don't have a lot of experience in using them myself as the build system we use at work doesn't seem to support it and we have gone down the path of including what we use. 4. Break your project up into a lot of static libraries, some build systems like Bazel make this quite easy to do. This could potentially mean less build time for small changes to code Good luck!
For the people who see Cherno selecting things weirdly like around 25:50, this can be done by pressing alt+shift and then select what you want. Absolute lifesaver!
For anyone stuck at 19:56, you now need to also include this to be able to use the stdout_color_mt function "#include spdlog/sinks/stdout_color_sinks.h"
If someone gets the error *'Unicode support requires compiling with /utf-8'* do this for both projects: 1. Open the project properties. 2. Select the Configuration Properties > C/C++ > Command Line property page. 3. In Additional Options, add the */utf-8* option to specify your preferred encoding. 4. Choose OK to save your changes.
Logging is a really important feature to have, good to see the early emphasis on this. Normally I'm really opposed to using macro's, but there is a redeeming feature when writing logs -- using __LINE__ and __FILE__ in your log messages will drastically improve their usefulness and are very tedious to write. Looking forward to the next installment :)
@@theo-dr2dz technically it can be done, but personally I don't think I'm typing std::source_location::current() every time I'm logging something. For my latest hobby project I do use std::source_location, together with macros to streamline its use.
Thank you these videos are great. I wish there were more tutorials that showed how to make large scale REAL PRODUCTION LEVEL software, instead of just constant little examples(though they have their place). I wish I knew of more tutorials like this!
These game engine series videos are living gold. When run out of ideas how to set something that it would make sense, I watch game engine series videos. Even though it is not closely related to making game engine.
Starting the series now but I'm excited to see that there's still Hazel content being created currently. Just became a happy patron of this project; can't wait to get caught up.
@@SuperCoolHandle94 Had a really good time working with hazel and this series. I think it's a great project and I've had to set it aside recently because my work schedule is busy af rn but I'd like to come back to it in the near future.
I am actually using cmake as the buildsystem. I had to setup the whole code in different cmakelists file as mentioned by cherno. FInding a library like spdlog which has support for cmake, it gives unimaginable happiness XD
I like this Logging API, been reviewing it for the last half hour or so. They have an Android example too, could use it in my Android C++ projects.... Edit, update: YESSS!!!! Logger up and functional, let's move on to the next one:)
If your getting to this part I highly recommend going to his Premake video and watching that quickly. Having Premake at this point in time helps with a lot of things and you can just downgrade any configurations that don't make sense yet.
To anyone who uses string.format in c#, use string interpolation instead. if you use a $ in front of a string, you can pass variables into the string like this $"The value of my variable is { myVar }"
hey there, first of all i want to thank you so much for this series. You are really doing a great job, taking your time teaching us all of your knowledge in a very smooth way even for non-native speakers like me (german). One thing i want to ask is: i usually try to avoid as much as possible to include things in my header files. f.e. here you included the stdlog stuff in the Log.h. What i did is that i included the spdlog and memory stuff in the .cpp file and moved all the specific stuff out of the header in the cpp. The little drawback for now is that i created a method for every type of log and passing in a "std::string" as a parameter, since at the moment we are just passing in strings, so i thought this might be enough for now. However im not quite sure if this is a wise idea, even though my header is only dependant on , which feels nicer. What do you think about that?
You should never return a shared_ptr by reference (&) - if you return it by reference, you won't properly increment the reference count, which opens up the risk of deleting something at the improper time.
Isn't returning handles like he does in GetCoreLogger() and GetClientLotter() violates the main rule why he wrapped the logging calls? Because the user can use these static functions to do whatever they want. In addition, those static methods return a logger specific variable which could be changed and then the client code should also be changed.
For whoever ends up testing all levels of log: there's no fatal log level in spdlog, but there is a critical level. I'd advise using it instaead of changing spdlog's code.
Interesting choice to recommend git submodules. I know this video is a couple of years old, and the C++ community certainly hasn't landed on a standard here, but I've found git submodules to be frustrating to use with lacking dependency resolution issues. Have you tried any package managers like conan?
Your goal was to wrap spdlog so we could theoretically replace it later. However you have just wrapped the initialization now, any caller still needs to interact with the spdlog API. Why not create a facade for spdlog that wraps all of the necessary API methods?
I noticed this too, including "spdlog/spdlog.h" in a header is not a very good idea as it now puts the burden on the client to include the vendor header file (This goes for any other vendor header file as the project goes on). It is much better to abstract the spdlog functions and interact with all thirdparty / vendor libs via the Hazel API.
On the off chance anyone else runs into the same issue that I did - specifically SandboxApp.obj : error LNK2001: unresolved external symbol private: static class std::shared_ptr Hazel::Log::s_CoreLogger. Make sure you don't have HZ_BUILD_DLL defined in your Preprocessor Definitions for your Sandbox app
For anyone having the LNK2001 issue: you will have to remove HZ_BUILD_DLL (or whatever your equivalent is to it) macro from the sandbox pre-processor definitions in the config. I hope this helped! if it didn't.. god help you.
@@emmanuelimmanuel Sandbox is the .Exe (executable) file that links to the Engine library (DLL) file. And inside the properties tab in the Sandbox file, you can find a tab called “preprocessor” you just need to remove the HZ_BUILD_DLL from it as it’s meant to be exclusive to the engine library.
@@MrArbaz25 00:26:15 I have problem here, HZ_CORE_WARN("Hazel Initialized!"); in EntryPoint. -- expression must have pointer-to-class type . Do you maybe know whats going on? this is my Log.h #define HZ_CORE_WARN(...) ::Hazel::Log::GetCoreLogger->warn(__VA_ARGS__). Without those macros everything works. Id like to know why this part is not working on my end. Thank you!
@@RootsterAnon haha, I got the same problem and manage to fix it. the problem is you forgot to put the bracket behind the "GetCoreLogger" and in front of the "->". this is what it should look like: HZ_CORE_WARN(...) ::Hazel::Log::GetCoreLogger()->warn(__VA_ARGS__) ~^~ you need this. without it, it is just gonna access the "GetCoreLogger" function and not the "s_CoreLogger".
Because of the way it has been included. When you include the Hazel header file, it will contain a #include "spdlog/spdlog.h" and your Sandbox project will not be able to find it. In my opinion, the spdlog functions should be abstracted into the Hazel library code so that client code doesn't know about spdlog.
Awesome video! I've watched your channel for so long and learn alot from you and I thank you for that! I wanted to ask you this for some time and if you mention it in this video I thought it's a good idea, can you make a video for CMake ? Thanks!
It doesn't compile completely cleanly at 21:04. Are the C4251 warnings not something that need tidying? Sorry if they're covered in other videos, this is the first I've watched in the series.
@@catinwall4256 "Bazel is a free software tool that allows for the automation of building and testing of software. The company Google uses the build tool Blaze internally and released an open-sourced part of the Blaze tool as Bazel, named as an anagram of Blaze." Source: Wikipedia
If the macro is expanded inside namespace Foo without the global scope resolution operator (first two colons) it becomes Foo::Hazel::etc which would not compile.
@@Redmile2006 I would need to know what the errors say. Make sure you've set up spdlog and included it in the project properly (your premake file and stuff is set properly) If you jump in the discord people should be more than willing to help (you can ping me if need be)
I have 2 warnings and 2 errors revolving around this: Warning C4251 " 'Hazel::Log::s_CoreLogger': class 'std::shared_ptr' needs to have dll-interface to be used by clients of class 'Hazel::Log' Hazel C:\HazelGameEngine\Hazel\Hazel\src\Hazel\Log.h" at line 27 What does it mean?
Love that you have logging, and up firs too but you have to be careful with others libraries and their licenses. With how easy it is to write color letters to console, and set position, could have just made one over 1 episode.
`inline` functions/methods are functions that don't get "called" like other functions which makes the app perform slower when functions get called a lot while it's running. So simply making a function inline is like copying its code and putting it wherever you call it and that eventually makes your program run faster. Note that we don't always use inline because it makes a copy of the function everytime you call it so that takes up some space, unless you have little functions like getter methods that simply won't worth giving them function calls so you just make them as inline.
i had to include Log.h in Entrypoint.h, cause otherwise it wouldnt compile, any ideas why ? have they changed something in VS or C++? extern and redeclaration doesnt work since it s a static function in a class
Make sure that #include "EntryPoint.h" (inside Hazel.h) is below all the other includes. The compiler reads from top to bottom... so if it doesn't see #include "Log.h" first then it thinks that its contents does not exist.
Hey Guys I am facing issue during linking: unresolved external symbol "private: static class std::shared_ptr GGENGINE::Log::s_CoreLogger". Can someone explain what is the cause for this? I renamed my engine to GGENGINE because I would become lazy and copy paste code the Git and tell myself I learnt something. atleast now I have to type it out at minimum.
I have a question . error LNK2001: Unresolved external symbol "private: static class std::shared_ptr Hazel::Log::s_CoreLogger" in SandboxApp.obj What is most likely the problem??
you could use the spdlog macros instead of the functions calls for the macro definition for it to be able to contain the line information and that good stuff
I think he was trying to take the things he wanted from spdlog and call them Hazel functions to have more flexibility with it. And of course, if all of the macros are prefixed the same way it becomes much easier to use them.
so i added the spdlog into the Project via Git but there is something wrong with it. i can actually see the vendor folder and all its subfolders. the spdlog folder contains all the files but they arrent loaded into the Project. 2 questions. 1. is this how its supposed to go in Visual Studio 2019 2. why i cant see this folder on the Screen from Cherno ? ^^ just confuced. thats all :D
I keep getting error LNK2001 using the logging functions in main(). I can only use them inside init(). EDIT: Turns out there's a big difference between _declspec and __declspec. I got errors using _declspec(dllexport) on the inline functions, but that was just intellisense being dumb again.
The core logger works fine but when I try to log something with the client logger I get an access violation exception thrown. I have looked into this video 100 times now but I cant seem to find the difference.I also tried to debug but it seems the Init function never gets called because breakpoints that I set in the function dont work yet the core logger works.
@@23CAREMUCH Wow this was a long time ago and since then I started like 2 or 3 times over trying to write a basic engine always choosing a different approach. I havent really solved it but instead I only have one project without a sandbox. I might change this in the future but for now I dont. So I have only have an Engine side logger which works fine for me. I know this does not really answer your question and I am sorry but this was too long ago to remember what I did and I also deleted my old projects.
@@23CAREMUCH When I was creating this I looked at the spdlog files before I would watch his video (just to see how far I could get before having to refer to his 'how-to'). With that, in "Log.cpp" when we set the "s_CoreLogger" to "spdlog::stdout_color_mt("Hazel")" I placed "auto in front of that line and the s_ClientLogger one - so "auto s_CoreLogger = spdlog::stdout_color_mt("Hazel");" - because that's what the spdlog files say to use. Though the "auto" is what caused the error - still not sure why though - so I simply deleted it in front of both lines and it works fine. I hope you find this useful if you're still needing the help even after 2 months.
I am still trying to understand the purpose of returning a shared pointer by reference. Semantically it seems to me that its intended to be returned by value?
spdlog is very slow to compile code with... I use printf formatting with macros for each type I try to format like: mCoreLogError( "path: " mFmtS, mFmtSValue( path ) ); and it will print smth like that: "[error] (render\device.cpp:195) path: C:\Windows"
Spent about an hour to find out that my version of visual studio wanted a backslash or it would generate an error "Cannot open include file: 'spdlog/spdlog.h': No such file or directory". $(SolutionDir)Hazel\vendor\spdlog\include; =Error $(SolutionDir)\Hazel\vendor\spdlog\include; =Working Hope this helps someone.
I had this too for a min, To fix it, in your init(), make sure you init s_CoreLogger and s_ClientLogger (while copt/pasting I forgot to change the name), then copy the .dll
Getting "the identifier __VA_ARGS__ can only appear in the replacement lists of variadic macros" error with __VA_ARGS__ in visual studio 2022, solution please
Why the main() function in EntryPoint.h can call Hazel::Log::Init() successfully without including the header "Log.h" ? Is it because of the namespace ?
What should I fix to run this on the latest VS2019? Everything correct, rewatched the last few videos. Compiler says: "Error LNK2001 unresolved external symbol "private: static class std::shared_ptr Hazel::Log::s_CoreLogger" (?s_CoreLogger@Log@Hazel@@0V?$shared_ptr@Vlogger@spdlog@@@std@@A)" The same thing with the ClientLogger...
I removed Log.cpp file and defined Init function inside the class in Log.h. Also I defined the 2 static variables once again in Log.h outside the namespace as std::shared_ptr Hazel::Log::s_CoreLogger; std::shared_ptr Hazel::Log::s_ClientLogger; If I keep the definition of Init in Log.cpp then I think SandBox.obj is not able to find Log.obj hence the Linker error. So removing Log.cpp file and just putting everything in Log.h file includes the definition of Init in Sandbox(because it includes Hazel.h). Also the declaring the static variables inside class is not counted as definition so we need to define them outside the class.
In my case the solution was doing the function declaration all in the cpp. When I did the function declaration of GetCoreLogger inside the hpp, I was calling the variable m_CoreLogger which in the hpp was defined but not declared. So its common that it was an unknown symbol for sandbox. Hope it helps someone
Hi, I know I'm pretty late to the party, but would anyone happen to know why I'm getting the following error? Severity Code Description Project File Line Suppression State Error LNK2001 unresolved external symbol "private: static class std::shared_ptr Hazel::Log::s_CoreLogger" (?s_CoreLogger@Log@Hazel@@0V?$shared_ptr@Vlogger@spdlog@@@std@@A) Sandbox C:\dev\Hazel\Sandbox\SandboxApp.obj 1 As far as I can tell my code is identical so I'm slightly confused. *EDIT*: There is a comment thread 10 months ago about this exact issue. The issue is a result of Core.h mis-typing the #else dllimport as #else dllexport! If this is your problem make sure you're importing on the else branch!!!
Why am I getting 64 errors and 16 warnings when I try to compile the Log.cpp file? 💀 They're all about format.h, xutility, __msvc_iter_core.hpp and a bit of iterator files Edit: Yeah I figured out that that happened because I switched C++ version from C++14 to C++20, I reset it to the default (C++14) and it worked just fine, these libraries are getting old, LOL. :)
m_ is for member variables of a class, s_ for static variables, I also use t_ for variables being passed into functions but they're about the only ones I ever use
How do you go about including part of a submodule (eg spdlog/include)? I understand you cannot clone part of a repo, so is there a way to perhaps filter out only what you want from the submodule?
All was going fine until I get to this video. The solution runs ok but I get 4 errors: E1866 attribute does not apply to any entity. 2 are in file "format.h" & 2 are in "core.h" Both of these files are in my Hazel\vendor\spdlog\include\spdlog\fmt\bundled folder. Any ideas are appreciated!
24:15 maybe use template variadic args instead of that ugly macro? Also, do we really need to use std::shared_ptr for the logger instance? If yes, please elaborate.
I think a singleton would have been better here than a shared pointer. The advantage of a shared pointer is of course shared ownership, but since he's got static instances of it here, he can't take advantage of that at all while still doing the reference counting that goes along with it. With each log call he's creating a temporary pointer that increases and decreases the reference count. Because shared pointers have to support multi threading, this is a rather slow process anyway Iirc, singletons implemented with static in a function are threadsafe as well. You get rid of all the reference counting and therefore a decent speed boost. Not sure from the top of my head if there's a check if the object is initialised each time you call the method, but it's definitely better than a shared pointer. Moreover, you can then put the init code into a constructor and so skip having to call the init function. Since it's included in the framework, it's not gonna be an issue in this case, of course, but I always like being able to take advantage of raii lastly, like mentioned here already, he could have used if constexpr to disable his functions for production builds. I don't think that's a compelling argument for macros. On the other hand, macros allow you to use other macros like __LINE__ that can be really useful when logging Edit: watched on mobile, so I didn't see he's returning references to the smart pointers only. The reference counting isn't that bad them, but using a shared pointer still doesn't seem sensible to me. On the other hand, he's generally more experienced than me, so he probably has some reason for it
does anybody have an idea why am I getting this error: E1393 a member of a class declared with dllexport/dllimport cannot itself be declared with such a specifier at this 18:12 part?
I copied everything correctly but whenever i run the project it opens but there is not logging showing up. Does anyone know what happened or how to fix it?
Guys i did exactly what he did but got 42 errors. So i decided to clone from his git repo and opened the complete finished Hazel, yet i have 829 errors which say syntax, can't open source files, undefined things, what am i doing wrong? :(
what is the error? 'std::copy_n::Unchecked iterators::_Deprecate' To disable this warning , use -D_SCL_SECURE_NO_WARNINGS and the same with 'std::copy'. I used D_SCL_SECURE_NO_WARNINGS with #define, but it needs to have a dash in front of this line. It doesn't want to define with a dash in front of that line, I'am trying to fix this error, but I have no results :( Help me, please, who knows how to fix this
@Artem Katerynych it talks about the file "xutility". I don't understand how to fix that) and It's is an error I have alredy described. Line is 2458)) Two errors about 'std::copy_n::Unchecked_iterators::' and two errors about 'std::copy::Unchecked_iterators::'. Error code is C4996
@Artem Katerynych Don't worry for late response. I have even more warnings as I disabled SDL checks, but if you strongly advise not to do this, I won't. I don't quite understand what deprecation errors means, but anyway I'm not going to disable that. I really don't know how to help you to help me fix the problem. I have no another error line number other than the one I have already discribed to you. I have only 4 error, the error line numbers are 2458 and 2372 in xutility. Debugger doesn't work with my code and I have no notion why. It is really weird. It just compiles my code and doesn't do anything else. Maybe, I have too small a level for this project?) But I want to finish no matter what. By the way, I also didn't understand the part about commenting the code
I'm encountering the same error. It seems, to me at least, to be a problem in the Sandbox project, because the Hazel project compiles without errors. [EDIT WITH SOLUTION]: You need to copy the include path with spdlog's include folder from the Hazel project to the Sandbox project. Both projects need access to that directory.
Thanks for watching guys, hope you enjoyed the video! Next episode is already available for Patrons on www.patreon.com/posts/22646119 ❤️
You forgot to release the logger code on github I guess?
An honest question. As game engine developer, I decided to use spdlog just as you, and was really interested, how do you tackle compile time? From my experience It adds from 2 to 5 seconds of compile time per file... I wonder, have you ever tackled this issue?
@@TheMesoria My experience with header only libraries is that you can either put them into a precompiled header file, or you abstract them into your main library. As a software developer, I see far too often people including header files within header files because their class contains a pointer/reference to an object. This is what slows build times because those header files need to be parsed for each cpp file that gets compiled. Making a change in a header file might propagate throughout your entire build hierarchy and your build system will want to build everything again.
If you are still having problems, there are a few methods you can try.
1. Use a Pimpl method if you have objects that really need their header files included. This pointer to implementation is quite good at abstracting your private fields of the class to inside of you source file. This is also very useful to contain those nasty header files with a ton of macros that cause more problems than they solve. This does mean another level of indirection to access your variables though. Perhaps the compiler can optimize this though although I have never tried to see if this was the case.
2. Move your header files to your source file and forward reference what you need in the header file. Quite often, you only need the type, and including the header is just wasted build time.
3. Use precompiled header files. Put a lot of the header files that you would otherwise end up including in your other source files into a precompiled header. A lot of the work will have already been done by the compiler, but I believe this might need to be used wisely. I don't have a lot of experience in using them myself as the build system we use at work doesn't seem to support it and we have gone down the path of including what we use.
4. Break your project up into a lot of static libraries, some build systems like Bazel make this quite easy to do. This could potentially mean less build time for small changes to code
Good luck!
For the people who see Cherno selecting things weirdly like around 25:50, this can be done by pressing alt+shift and then select what you want. Absolute lifesaver!
For anyone stuck at 19:56, you now need to also include this to be able to use the stdout_color_mt function "#include spdlog/sinks/stdout_color_sinks.h"
Thank you very much!
@@Windeycastle he said it later in the video but we’re all impatient an got Stuck ahah
@@SuperCoolHandle94 I noticed as well, whoops. It took longer to find the answer then it would have to keep watching
Thank You
Thanks!
If someone gets the error *'Unicode support requires compiling with /utf-8'* do this for both projects:
1. Open the project properties.
2. Select the Configuration Properties > C/C++ > Command Line property page.
3. In Additional Options, add the */utf-8* option to specify your preferred encoding.
4. Choose OK to save your changes.
Logging is a really important feature to have, good to see the early emphasis on this.
Normally I'm really opposed to using macro's, but there is a redeeming feature when writing logs -- using __LINE__ and __FILE__ in your log messages will drastically improve their usefulness and are very tedious to write.
Looking forward to the next installment :)
Your code was italic'd
C++20 has std::source_location so now that can be done without macro's
@@theo-dr2dz technically it can be done, but personally I don't think I'm typing std::source_location::current() every time I'm logging something. For my latest hobby project I do use std::source_location, together with macros to streamline its use.
I didn't know you could do that! Thanks for commenting!
The logger word "fatal" is apparently replaced with "critical" in the newer versions (as of writing this comment)
Thank you!
Thank You
Probably for the best.
yes W
Thank you these videos are great. I wish there were more tutorials that showed how to make large scale REAL PRODUCTION LEVEL software, instead of just constant little examples(though they have their place). I wish I knew of more tutorials like this!
The best programming channel. Thanks, Cherno!
Checkout javidx9 channel.
Exactly.. the best of all
I really like how you started with logging for the first feature. Very important and underrated part of an engine!
These techniques you are using here are really advanced, with this I can improve my C++ knowledge, thanks.
These game engine series videos are living gold. When run out of ideas how to set something that it would make sense, I watch game engine series videos. Even though it is not closely related to making game engine.
But this is making a game engine. Well, an engine.
Starting the series now but I'm excited to see that there's still Hazel content being created currently. Just became a happy patron of this project; can't wait to get caught up.
howd you go Gabe? im just starting an seeing as you're only 2 months ahead of me i thought id ask
@@SuperCoolHandle94 Had a really good time working with hazel and this series. I think it's a great project and I've had to set it aside recently because my work schedule is busy af rn but I'd like to come back to it in the near future.
@@gabesusman4592progress report!!
I am actually using cmake as the buildsystem. I had to setup the whole code in different cmakelists file as mentioned by cherno. FInding a library like spdlog which has support for cmake, it gives unimaginable happiness XD
I like this Logging API, been reviewing it for the last half hour or so.
They have an Android example too, could use it in my Android C++ projects....
Edit, update:
YESSS!!!!
Logger up and functional, let's move on to the next one:)
Amazing work, Yan. You’ve definitely learned a lot since Sparky, and I appreciate you sharing what you’ve learned.
"I really like to know what's going on'. Me too. Logging is life saver.
Absolutely love your tutorials brother. I learn more from you than from any other single source. You rock.
I'm following your game engine series alongside some textbooks and I am learning SOOO much by example. Thank you so much!
If your getting to this part I highly recommend going to his Premake video and watching that quickly. Having Premake at this point in time helps with a lot of things and you can just downgrade any configurations that don't make sense yet.
I've made my own simple logger with the ansii color codes. Works fine and code is very small. ;)
That’s what I did as well. Don’t know why Cherno decided to use a logging library
Im so grateful that ur doing this series... Thanks!
To anyone who uses string.format in c#, use string interpolation instead.
if you use a $ in front of a string, you can pass variables into the string like this
$"The value of my variable is { myVar }"
hey there, first of all i want to thank you so much for this series. You are really doing a great job, taking your time teaching us all of your knowledge in a very smooth way even for non-native speakers like me (german).
One thing i want to ask is: i usually try to avoid as much as possible to include things in my header files. f.e. here you included the stdlog stuff in the Log.h.
What i did is that i included the spdlog and memory stuff in the .cpp file and moved all the specific stuff out of the header in the cpp. The little drawback for now is that i created a method for every type of log and passing in a "std::string" as a parameter, since at the moment we are just passing in strings, so i thought this might be enough for now.
However im not quite sure if this is a wise idea, even though my header is only dependant on , which feels nicer. What do you think about that?
nvm me. passing the arguments requires more efforts for this... though the idea might be good ?!
You should never return a shared_ptr by reference (&) - if you return it by reference, you won't properly increment the reference count, which opens up the risk of deleting something at the improper time.
Isn't returning handles like he does in GetCoreLogger() and GetClientLotter() violates the main rule why he wrapped the logging calls? Because the user can use these static functions to do whatever they want. In addition, those static methods return a logger specific variable which could be changed and then the client code should also be changed.
For whoever ends up testing all levels of log: there's no fatal log level in spdlog, but there is a critical level. I'd advise using it instaead of changing spdlog's code.
thanks I was confused there for a second
Best series ever !
If I could have been a patreon I would have
GL ❤❤
Interesting choice to recommend git submodules. I know this video is a couple of years old, and the C++ community certainly hasn't landed on a standard here, but I've found git submodules to be frustrating to use with lacking dependency resolution issues. Have you tried any package managers like conan?
23:47 I have a little (probably stupid) question, why add double semicolons in front? I removed them and it worked fine.
If you remove them: using the macro inside the Hazel namespace will not compile.
Your goal was to wrap spdlog so we could theoretically replace it later. However you have just wrapped the initialization now, any caller still needs to interact with the spdlog API. Why not create a facade for spdlog that wraps all of the necessary API methods?
I noticed this too, including "spdlog/spdlog.h" in a header is not a very good idea as it now puts the burden on the client to include the vendor header file (This goes for any other vendor header file as the project goes on). It is much better to abstract the spdlog functions and interact with all thirdparty / vendor libs via the Hazel API.
it's so hard. espcially if you don't know well english like me, but so important tutorial. Thank you very much all of them
9:34 "kind of" like 10 times haha
that's kind of really funny
On the off chance anyone else runs into the same issue that I did - specifically SandboxApp.obj : error LNK2001: unresolved external symbol private: static class std::shared_ptr Hazel::Log::s_CoreLogger. Make sure you don't have HZ_BUILD_DLL defined in your Preprocessor Definitions for your Sandbox app
Thanks ;)
Damn, you're a life saver. Thanks 👍
YO i started over twice thinking i did something wrong!! sir you are a life saver! Thank you!!
You're my hero
btw, to get rid of that warning, above class HAZEL_API Log you just need to write template class HAZEL_API std::shared_ptr;
For anyone having the LNK2001 issue:
you will have to remove HZ_BUILD_DLL (or whatever your equivalent is to it) macro from the sandbox pre-processor definitions in the config. I hope this helped! if it didn't.. god help you.
thank you very much ,I wonder why
what is the sandbox preprocessor
@@emmanuelimmanuel Sandbox is the .Exe (executable) file that links to the Engine library (DLL) file. And inside the properties tab in the Sandbox file, you can find a tab called “preprocessor” you just need to remove the HZ_BUILD_DLL from it as it’s meant to be exclusive to the engine library.
Thanks, it really helped me to kick start the logging using sdplog
"#define HZ_CORE_TRACE(...) ::Hazel::Log::GetCoreLogger()->trace(__VA_ARGS__)" ,why do you put “::” in front of Hazel?
An empty :: infront of an identifier represents a global scope. So, this ::Hazel means in the global scope there is a Hazel namespace.
@@MrArbaz25 00:26:15 I have problem here, HZ_CORE_WARN("Hazel Initialized!"); in EntryPoint. -- expression must have pointer-to-class type . Do you maybe know whats going on? this is my Log.h #define HZ_CORE_WARN(...) ::Hazel::Log::GetCoreLogger->warn(__VA_ARGS__). Without those macros everything works. Id like to know why this part is not working on my end. Thank you!
@@RootsterAnon GetCoreLogger is a function that returns a static pointer variable, *not a variable*. So you should edit it as GetCoreLogger().
@@aldeywahyuputra5719 thank you!
@@RootsterAnon haha, I got the same problem and manage to fix it. the problem is you forgot to put the bracket behind the "GetCoreLogger" and in front of the "->".
this is what it should look like:
HZ_CORE_WARN(...) ::Hazel::Log::GetCoreLogger()->warn(__VA_ARGS__)
~^~
you need this. without it, it is just gonna access the "GetCoreLogger" function and not the "s_CoreLogger".
Why do we need to include spdlog library in the sandbox project? Is't it should be added in the Hazel dll?
Because of the way it has been included. When you include the Hazel header file, it will contain a #include "spdlog/spdlog.h" and your Sandbox project will not be able to find it. In my opinion, the spdlog functions should be abstracted into the Hazel library code so that client code doesn't know about spdlog.
std::format in C++ 20 🔥
Awesome video! I've watched your channel for so long and learn alot from you and I thank you for that! I wanted to ask you this for some time and if you mention it in this video I thought it's a good idea, can you make a video for CMake ? Thanks!
It doesn't compile completely cleanly at 21:04. Are the C4251 warnings not something that need tidying? Sorry if they're covered in other videos, this is the first I've watched in the series.
Obviously nothing he needs to care about at this point. Did you read the warnings?
_SCL_SECURE_NO_WARNINGS add this in you Hazel.dll -> Properties -> c/c++ -> Preprocessor Definitions. on in our Log.h header
how about using bazel as a build system?
🅱azel
stop...I hate that meme.
basel is a food, meister. what are you thinking?
@@catinwall4256 "Bazel is a free software tool that allows for the automation of building and testing of software. The company Google uses the build tool Blaze internally and released an open-sourced part of the Blaze tool as Bazel, named as an anagram of Blaze." Source: Wikipedia
hey people, Replace _FATAL with _CRITICAL and replace ->fatal(__VA_ARGS__) with ->critical(__VA_ARGS__)
24:06 why is in the the macro beginning with ::Hazel:: and not with just Hazel:: ?
If the macro is expanded inside namespace Foo without the global scope resolution operator (first two colons) it becomes Foo::Hazel::etc which would not compile.
@@toddeburch thanks a lot. finally enlightment
I need to bookmark these 3rd party libraries for future use.
I keep getting error: stdout_color_mt is not a member of spdlog
Make sure you are including
#include "spdlog/sinks/stdout_color_sinks.h"
@@Ultamatum0502 I did that and it increased my errors, now there are 12 errors
@@Redmile2006 I would need to know what the errors say.
Make sure you've set up spdlog and included it in the project properly (your premake file and stuff is set properly)
If you jump in the discord people should be more than willing to help (you can ping me if need be)
@@Ultamatum0502 Can I add you on discord in case I need help?
@@emhean I mean if you want sure PM me and I'll send you my details, but honestly you'll probs get more help from the cherno discord.
I have 2 warnings and 2 errors revolving around this:
Warning C4251
" 'Hazel::Log::s_CoreLogger': class 'std::shared_ptr' needs to have dll-interface to be used by clients of class 'Hazel::Log' Hazel C:\HazelGameEngine\Hazel\Hazel\src\Hazel\Log.h" at line 27
What does it mean?
idk i have it too
Love that you have logging, and up firs too
but you have to be careful with others libraries and their licenses.
With how easy it is to write color letters to console, and set position, could have just made one over 1 episode.
did you even watch the video before posting this?
So much bloom in your camera shot, should look into that
Why make the static GetLogger member functions inline? (is it because it's define in the header file? But why define it in header in the first place?)
`inline` functions/methods are functions that don't get "called" like other functions which makes the app perform slower when functions get called a lot while it's running.
So simply making a function inline is like copying its code and putting it wherever you call it and that eventually makes your program run faster.
Note that we don't always use inline because it makes a copy of the function everytime you call it so that takes up some space, unless you have little functions like getter methods that simply won't worth giving them function calls so you just make them as inline.
Watching you at 0.9 playback speed really helps alot.
If you have issues with spdlog rember to include vendor/spdlog/include to the project, but only include folder, keep rest excluded
Second I get a job im jumping on that patreon my god man
use the c build system. make an executable that uses system() and a .txt file to execute all of the necessary libraries
You're the best! Thanks a lot :)
i had to include Log.h in Entrypoint.h, cause otherwise it wouldnt compile, any ideas why ? have they changed something in VS or C++?
extern and redeclaration doesnt work since it s a static function in a class
Make sure that #include "EntryPoint.h" (inside Hazel.h) is below all the other includes. The compiler reads from top to bottom... so if it doesn't see #include "Log.h" first then it thinks that its contents does not exist.
@@gustavstreicher4867 that was kind of a life saver, thanks a lot
Hey Guys I am facing issue during linking: unresolved external symbol "private: static class std::shared_ptr GGENGINE::Log::s_CoreLogger". Can someone explain what is the cause for this?
I renamed my engine to GGENGINE because I would become lazy and copy paste code the Git and tell myself I learnt something. atleast now I have to type it out at minimum.
hey i have the same issuse did u ever fix it
I have a question .
error LNK2001: Unresolved external symbol "private: static class std::shared_ptr Hazel::Log::s_CoreLogger" in SandboxApp.obj
What is most likely the problem??
Remove define BUILD_DLL in Sandbox project
@@anonimiangels5091 I tried your suggestion and it can be compiled, but what is the reason for this, can you explain it?
The latest Visual Studio 2019 16.6.2 broke spdlog... (in spdlog/fmt/bundled/core.h)
you could use the spdlog macros instead of the functions calls for the macro definition for it to be able to contain the line information and that good stuff
I think he was trying to take the things he wanted from spdlog and call them Hazel functions to have more flexibility with it. And of course, if all of the macros are prefixed the same way it becomes much easier to use them.
so i added the spdlog into the Project via Git but there is something wrong with it. i can actually see the vendor folder and all its subfolders. the spdlog folder contains all the files but they arrent loaded into the Project.
2 questions.
1. is this how its supposed to go in Visual Studio 2019
2. why i cant see this folder on the Screen from Cherno ? ^^
just confuced. thats all :D
I keep getting error LNK2001 using the logging functions in main(). I can only use them inside init().
EDIT: Turns out there's a big difference between _declspec and __declspec. I got errors using _declspec(dllexport) on the inline functions, but that was just intellisense being dumb again.
The core logger works fine but when I try to log something with the client logger I get an access violation exception thrown. I have looked into this video 100 times now but I cant seem to find the difference.I also tried to debug but it seems the Init function never gets called because breakpoints that I set in the function dont work yet the core logger works.
Did you get a fix for this? I'm getting the same issues. Would appreciate the help :)
@@23CAREMUCH Wow this was a long time ago and since then I started like 2 or 3 times over trying to write a basic engine always choosing a different approach. I havent really solved it but instead I only have one project without a sandbox. I might change this in the future but for now I dont. So I have only have an Engine side logger which works fine for me. I know this does not really answer your question and I am sorry but this was too long ago to remember what I did and I also deleted my old projects.
@@23CAREMUCH When I was creating this I looked at the spdlog files before I would watch his video (just to see how far I could get before having to refer to his 'how-to'). With that, in "Log.cpp" when we set the "s_CoreLogger" to "spdlog::stdout_color_mt("Hazel")" I placed "auto in front of that line and the s_ClientLogger one - so "auto s_CoreLogger = spdlog::stdout_color_mt("Hazel");" - because that's what the spdlog files say to use. Though the "auto" is what caused the error - still not sure why though - so I simply deleted it in front of both lines and it works fine.
I hope you find this useful if you're still needing the help even after 2 months.
I solved that, im so glad. The problem was that i didnt saved the files before copying the dll from Hazel folder to Sandbox folder
I had a similar issue. For me it was due to the fact that I wasn't calling Log::Init() before trying to use it.
definition of dllimport static data member not allowed.
Code is correct for the __declspec
I'm getting this error but I have no idea why
I am still trying to understand the purpose of returning a shared pointer by reference. Semantically it seems to me that its intended to be returned by value?
For performance, otherwise the atomic counter that tracks usages will be incremented and decremented with the lifetime of the temporary.
I got those get...loggers functions as unresolved externals. Please help.
yeah me too
me too
How did you fix this?
Nice really interesting !
I love your channel:)) thanks for your hard work for us:)) regards
In case you following this, checkout, and get spdlog not found error, do: git submodule update --init
Thank you thank you
spdlog is very slow to compile code with... I use printf formatting with macros for each type I try to format like: mCoreLogError( "path: " mFmtS, mFmtSValue( path ) ); and it will print smth like that: "[error] (render\device.cpp:195) path: C:\Windows"
Why didn't you use the singleton design pattern when you declared the logging class?
Spent about an hour to find out that my version of visual studio wanted a backslash or it would generate an error "Cannot open include file: 'spdlog/spdlog.h': No such file or directory".
$(SolutionDir)Hazel\vendor\spdlog\include; =Error
$(SolutionDir)\Hazel\vendor\spdlog\include; =Working
Hope this helps someone.
Thanks :)
Great and clear!
Does the logger really need to be a class? You could get away with some functions, easily.
Is it possible to set the priority for the log, so that we can obtain log records with different priorities from different Layers through filters
Thank you
The GetClientLogger()->warn(...) seems to cause a crash
I had this too for a min,
To fix it, in your init(), make sure you init s_CoreLogger and s_ClientLogger (while copt/pasting I forgot to change the name), then copy the .dll
@@jahardey5709 Same, thanks for the help
Getting "the identifier __VA_ARGS__ can only appear in the replacement lists of variadic macros" error with __VA_ARGS__ in visual studio 2022, solution please
Why the main() function in EntryPoint.h can call Hazel::Log::Init() successfully without including the header "Log.h" ? Is it because of the namespace ?
OK I see it is included in Hazel.h which is included in Sandbox.cpp.
There doesn't seem to be 'fatal' logging in the library, I might be doing something wrong though
->critical is what should have been called instead of fatal. I think he just missed it because his intellisense stopped working.
Great video! :D
What should I fix to run this on the latest VS2019? Everything correct, rewatched the last few videos.
Compiler says: "Error LNK2001 unresolved external symbol "private: static class std::shared_ptr Hazel::Log::s_CoreLogger" (?s_CoreLogger@Log@Hazel@@0V?$shared_ptr@Vlogger@spdlog@@@std@@A)"
The same thing with the ClientLogger...
I removed Log.cpp file and defined Init function inside the class in Log.h. Also I defined the 2 static variables once again in Log.h outside the namespace as
std::shared_ptr Hazel::Log::s_CoreLogger;
std::shared_ptr Hazel::Log::s_ClientLogger;
If I keep the definition of Init in Log.cpp then I think SandBox.obj is not able to find Log.obj hence the Linker error. So removing Log.cpp file and just putting everything in Log.h file includes the definition of Init in Sandbox(because it includes Hazel.h). Also the declaring the static variables inside class is not counted as definition so we need to define them outside the class.
I found the real reason - missed putting HAZEL_API macro in Log.h . See - 14:56
In my case the solution was doing the function declaration all in the cpp. When I did the function declaration of GetCoreLogger inside the hpp, I was calling the variable m_CoreLogger which in the hpp was defined but not declared. So its common that it was an unknown symbol for sandbox. Hope it helps someone
@@kishorab Still not working bro
what should I do?
My Log.h file is given below,
//Log.h
#pragma once
#include "Remie_Core.h"
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
namespace Remie {
class REMIE_API Log {
public:
static void Init() {
spdlog::set_pattern("%^[%T] %n: %v%$");
s_CoreLogger = spdlog::stdout_color_mt("REMIE");
s_CoreLogger->set_level(spdlog::level::trace);
s_ClientLogger = spdlog::stdout_color_mt("APP");
s_ClientLogger->set_level(spdlog::level::trace);
}
static std::shared_ptr& GetCoreLogger() { return s_CoreLogger; }
static std::shared_ptr& GetClientLogger() { return s_ClientLogger; }
private:
static std::shared_ptr s_CoreLogger;
static std::shared_ptr s_ClientLogger;
};
std::shared_ptr Remie::Log::s_CoreLogger;
std::shared_ptr Remie::Log::s_ClientLogger;
}
@@kishorab tried your solution, still not working for me :/
Hi, I know I'm pretty late to the party, but would anyone happen to know why I'm getting the following error?
Severity Code Description Project File Line Suppression State
Error LNK2001 unresolved external symbol "private: static class std::shared_ptr Hazel::Log::s_CoreLogger" (?s_CoreLogger@Log@Hazel@@0V?$shared_ptr@Vlogger@spdlog@@@std@@A) Sandbox C:\dev\Hazel\Sandbox\SandboxApp.obj 1
As far as I can tell my code is identical so I'm slightly confused.
*EDIT*: There is a comment thread 10 months ago about this exact issue. The issue is a result of Core.h mis-typing the #else dllimport as #else dllexport! If this is your problem make sure you're importing on the else branch!!!
Me too !! i was about to kill myself , i fucking love you to piece
that's enough headache for today
PLEASE HELP
I DONT HAVE IT WRONG BUT IM STILL GETTING THE ERROR :(
a year later and still a lifesaver. Thanks Man!!!
Dude thank you
Why am I getting 64 errors and 16 warnings when I try to compile the Log.cpp file? 💀
They're all about format.h, xutility, __msvc_iter_core.hpp and a bit of iterator files
Edit:
Yeah I figured out that that happened because I switched C++ version from C++14 to C++20, I reset it to the default (C++14) and it worked just fine, these libraries are getting old, LOL. :)
What does the s_ prefix stand for in e.g. s_ClientLogger?
In other videos I‘ve seen the prefix m_, what does that mean?
Thanks
m_ is a common way to denote private visibilty in a c++ class :)
Not sure about s_, though I'd assume it to be similar.
static
m_ is for member variables of a class, s_ for static variables, I also use t_ for variables being passed into functions but they're about the only ones I ever use
How do you go about including part of a submodule (eg spdlog/include)? I understand you cannot clone part of a repo, so is there a way to perhaps filter out only what you want from the submodule?
All was going fine until I get to this video.
The solution runs ok but I get 4 errors: E1866 attribute does not apply to any entity.
2 are in file "format.h" & 2 are in "core.h" Both of these files are in my Hazel\vendor\spdlog\include\spdlog\fmt\bundled folder.
Any ideas are appreciated!
what commit is his spdlog on? Our spdlog submodule has to be on the same commit as his
What about these warning at 19:35 (" needs to have dll-interface...")? Should I be worried?
I got this too. Any solution? Mine won't build.
24:15 maybe use template variadic args instead of that ugly macro?
Also, do we really need to use std::shared_ptr for the logger instance? If yes, please elaborate.
He explained in the video why he's using the macros. Using macros makes it easier to disable all logging in the distribution builds.
@@andre_van_duin I think there are some modern tools to do exactly that, for example enable_if and constexpr if
I think a singleton would have been better here than a shared pointer. The advantage of a shared pointer is of course shared ownership, but since he's got static instances of it here, he can't take advantage of that at all while still doing the reference counting that goes along with it. With each log call he's creating a temporary pointer that increases and decreases the reference count. Because shared pointers have to support multi threading, this is a rather slow process anyway
Iirc, singletons implemented with static in a function are threadsafe as well. You get rid of all the reference counting and therefore a decent speed boost. Not sure from the top of my head if there's a check if the object is initialised each time you call the method, but it's definitely better than a shared pointer. Moreover, you can then put the init code into a constructor and so skip having to call the init function. Since it's included in the framework, it's not gonna be an issue in this case, of course, but I always like being able to take advantage of raii
lastly, like mentioned here already, he could have used if constexpr to disable his functions for production builds. I don't think that's a compelling argument for macros. On the other hand, macros allow you to use other macros like __LINE__ that can be really useful when logging
Edit: watched on mobile, so I didn't see he's returning references to the smart pointers only. The reference counting isn't that bad them, but using a shared pointer still doesn't seem sensible to me. On the other hand, he's generally more experienced than me, so he probably has some reason for it
Wouldn't it be better to use a `decltype(...)` for the return value type at 17:30? What are the pro's and con's of typing it explicitly?
does anybody have an idea why am I getting this error:
E1393 a member of a class declared with dllexport/dllimport cannot itself be declared with such a specifier at this 18:12 part?
i always come back to your videos for information.
GetCoreLogger not a member of 'Hazel'?
Figured it out. In log.h, the define's weren't set to use the log class inside the Hazel namespace. ::Hazel::log::GetCoreLogger() worked
update again. I just realised that was what he typed, but i forgot it
@Jens Karlsson oh shit it's been a while 😂
i posted the best reply solution in a reply above
Best C++ tutorials ever
I copied everything correctly but whenever i run the project it opens but there is not logging showing up. Does anyone know what happened or how to fix it?
Guys i did exactly what he did but got 42 errors. So i decided to clone from his git repo and opened the complete finished Hazel, yet i have 829 errors which say syntax, can't open source files, undefined things, what am i doing wrong? :(
it prints the message, but it doesnt change color... why?
what is the error? 'std::copy_n::Unchecked iterators::_Deprecate' To disable this warning , use -D_SCL_SECURE_NO_WARNINGS
and the same with 'std::copy'. I used D_SCL_SECURE_NO_WARNINGS with #define, but it needs to have a dash in front of this line. It doesn't want to define with a dash in front of that line, I'am trying to fix this error, but I have no results :( Help me, please, who knows how to fix this
@Artem Katerynych it talks about the file "xutility". I don't understand how to fix that) and It's is an error I have alredy described. Line is 2458)) Two errors about 'std::copy_n::Unchecked_iterators::' and two errors about 'std::copy::Unchecked_iterators::'. Error code is C4996
@Artem Katerynych thank you for the answer
@Artem Katerynych I can't go ahead because of these errors I get
@Artem Katerynych Don't worry for late response. I have even more warnings as I disabled SDL checks, but if you strongly advise not to do this, I won't. I don't quite understand what deprecation errors means, but anyway I'm not going to disable that. I really don't know how to help you to help me fix the problem. I have no another error line number other than the one I have already discribed to you. I have only 4 error, the error line numbers are 2458 and 2372 in xutility. Debugger doesn't work with my code and I have no notion why. It is really weird. It just compiles my code and doesn't do anything else. Maybe, I have too small a level for this project?) But I want to finish no matter what. By the way, I also didn't understand the part about commenting the code
Guys please help me I am facing an error
Error C1083 Cannot open include file: 'spdlog/spdlog.h': No such file or directory Hazel
I'm encountering the same error. It seems, to me at least, to be a problem in the Sandbox project, because the Hazel project compiles without errors.
[EDIT WITH SOLUTION]: You need to copy the include path with spdlog's include folder from the Hazel project to the Sandbox project. Both projects need access to that directory.
@@Prometheus_-ns2nn Thanks bro got it Worked fine (y)
@@Prometheus_-ns2nn Could you expand on this solution? I'm trying to follow it, but unfortunately I keep getting this C1083 error.
مجهود رائع